# -*- coding: utf-8 -*-
import copy
import time
import platform
from scipy.spatial.distance import cdist
from scipy.optimize import linear_sum_assignment
from src._3_trackProcess.tracking import KalmanTracking
from src._3_trackProcess.redis import getRedis, getRedisOutside, getRedisOutsidetemp
from src._3_trackProcess.paint import cv2ImgAddText
from src._4_utils.log import log, cfg
import shutil
from src._4_utils.Com_Pt2Gps import *
import traceback
import datetime
import cv2
import base64
import json
import numpy as np
from videoPush import VideoPusher  # 视频推送模块
import os
from src._2_aisImer.utils import *


def pick_top1_ais_dict(ais_dict):
    for key, value in list(ais_dict.items()):
        try:
            # key大于1时才进行删除操作
            num_keys = len(ais_dict[key].keys())
            # 对key进行排序操作
            key_list = sorted(ais_dict[key].keys())
            if int(num_keys) > 1:
                for key2, value2 in list(ais_dict[key].items()):
                    # 只保留两个最大的key值
                    if key2 == key_list[-1]:
                        continue
                    else:

                        ais_dict[key].pop(key2)
        except:
            log.logger.error(traceback.format_exc())

    return ais_dict


class trackProcess:
    def __init__(self, init):
        self.init = init
        self.tracker = KalmanTracking(IOUThreshold=init['track_iou_threshold'],
                                      removeTrackAfternFramesThres=init['track_remove_after_n_frames_thr'],
                                      uncertaintyCount=init['track_uncertainty_count'])
        self.object_list = []  # 存放目标列表，供索引用
        self.object_dict_push = {}  # 存放推送的目标字典（确定目标，用于计算ais融合）
        self.box_count = {}  # 存放每一个待确定目标点的box，动态信息，（用于计算船舶速度、船舶长度）
        self.box_count_confirm = {}  # 存放每一个确定目标点的box，动态信息，（用于判断是否为停泊船）
        self.ais_imerge_info = {}  # 存放ais融合的信息
        self.ais_pick = {}  # ais与目标对应字典{key:mmsi  value:id}
        self.object_confirm_roi = init['roi_set']  # 检测框roi
        self.Hm = init['cam_hm']  # 相机安装高度
        self.vpr = init['vpr']  # 相机vpr
        self.ship_speed_calculate = Ship_speed_calculate(init)  # 速度模块初始化
        self.ship_arguments_calculate = Ship_arguments_calculate(init)  # 船舶参数计算模块
        self.count = 0
        # self.pop_ais = init['ais_excludeMmsi']  # 需要剔除的ais信息
        self.pop_ais = []  # 需要剔除的ais信息
        self.ais_imerge_count = 0  # 用于控制ais融合
        self.ais_point_dict_copy = {}  # 深拷贝ais信息，以防多线程在更新字典报错
        self.snap_task_key_name = init['redis_out_res_task_key_name']
        self.no_push_id = []  # 不推送的id列表，比如是停泊船
        self.no_push_id_dict = {}  # 不推送的id字典，包含id和box，主要用于不预测停泊船，解决正常船舶与停泊船并行时，id错位（目标确认交并比设置太小时会出现该情况）
        self.pusher = VideoPusher(init)
        # 临时存放的字典
        self.temppusher = {}
        # self.res_task_key_name_box = init['res_task_key_name_box']  # 往redis里推送的视频帧钟的box数据
        self.res_task_key_name_frame = init['res_task_key_name_frame']
        self.para_state = True
        self.trackers_C = None
        # 并行船存放字典
        self.parallelship_dict = {}
        # 并行船预测次数
        self.parallelship_predict_count = {}
        self.r = getRedis()
        self.r_outside = getRedisOutside() if self.init['videoPushOutside_activate'] == 1 else ''
        self.r_outside_temp = getRedisOutside() if self.init['videoPushOutside_activate'] == 1 else ''
        self.dict_mmsi_shipname = get_local_dataset(init['local_dateset'])
        # self.illegal_ship_roi = init['illegal_ship_roi']
        # self.park_ship_iou = init['park_ship_iou']

    # def create_pusher(self):
    #     if self.object_list:
    #         for i in li

    def track_object(self, count, frame, frame_detect_box, ais_point_dict, detectConfidence):
        currentime = str(datetime.datetime.now()).replace("-", "/")[0:19].replace("/", "").replace(" ", "").replace(":",
                                                                                                                    "")
        section1_start = time.time()  # 结束时间
        if frame_detect_box:
            log.logger.info("{}收到的检测数据为{}".format(str(currentime), frame_detect_box))

        # log.logger.debug("确定状态的列表为{}".format(self.trackers_C))
        #
        # log.logger.info(
        #     "第{}帧检测到的frame_detect_box为{}".format(self.count, frame_detect_box))

        # 如果当前检测船舶数和上一帧预测的船舶数相等，且都为1，进行当前检测质量判断（适用于内河船），过滤强光等情况下某帧船舶检测异常情况。
        try:
            # calculate_iou
            # if len(self.trackers_C) == 1 and self.trackers_C[0][:4]!= [1.0,1.0,2.0,2.0]:
            # if len(self.trackers_C) == 1 and [int(t) for t in self.trackers_C[0, :].tolist()][0:-1] !=[1, 1, 2, 2] and int(self.init['fun_select']) == 0:
            if len(self.trackers_C) == 1 and [int(t) for t in self.trackers_C[0, :].tolist()][0:-1] != [1, 1, 2, 2]:
                # id_box_push = [int(t) for t in self.trackers_C[0, :].tolist()][0:-1]
                # print("id_box_push", id_box_push)
                if len(frame_detect_box) == 1:
                    most_similar = self.find_most_roi(self.trackers_C[0], frame_detect_box)
                    if not most_similar:
                        frame_detect_box = [[1, 1, 2, 2]]
                        log.logger.debug(
                            "第{}帧检测frame_detect_box和self.trackers_C相似度为{}".format(self.count, most_similar))
        except:
            log.logger.error(traceback.format_exc())
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧收到的去重ais数据为{}".format(self.count, ais_point_dict))

        now = datetime.datetime.now()
        # 每日0点的时候更新参数，以及状态为True，更新完之后状态改为false，以防重复更新状态
        if now.hour == 0 and now.minute == 0 and self.para_state:
            log.logger.debug("当前时间为{}，更新参数".format(now))
            self.update_para()
            self.para_state = False
        # 初始化frame_box_字典
        frame_box_dict = {
            "aisShipName": "",
            "aisMmsi": "",
            "snapDistance": "",
            "currentState": "",
            "aisShipSpd": -1,
            "islyingDown": -1,
            "isReverse": -1,
            "isOverTaking": -1,
            "detBox": ""}
        # 过滤异常的检测框
        frame_detect_box = [item for item in frame_detect_box if
                            int(item[0]) < int(item[2]) and int(item[1]) < int(item[3])]
        # 根据宽高比和面积进行过滤
        frame_detect_box = [box for box in frame_detect_box if
                            float((box[2] - box[0]) / (box[3] - box[1])) >= self.init["shipWH_ratio"] and (
                                    box[2] - box[0]) * (box[3] - box[1]) >= self.init["ship_area"]]
        log.logger.debug("第{}帧过滤后的检测数据为{}".format(self.count, frame_detect_box))
        if not frame_detect_box:
            # 如果未检测到box，初始化一个测试box
            frame_detect_box = [[1, 1, 2, 2]]
        # C:确定状态 U:不确定状态 M:丢失状态  D：deleted
        # try:

        section1_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧跟踪section1处理耗时{:.6}，秒".format(self.count, section1_end - section1_start))
        self.count = count
        self.frame = frame
        del_frame_list = []
        ####去掉frame_detect_box中的停泊船,从源头减少停泊船的影响,暂时不能去掉，去掉的话系统观感差
        # if self.no_push_id_dict:
        #     for k, v in self.no_push_id_dict.items():
        #         t = self.find_most_roi(self.no_push_id_dict[k], frame_detect_box)
        #         log.logger.debug("k为{}，box为{}，与列表中的{}相似度超过0.7，为停泊船，进行过滤".format(k, self.no_push_id_dict[k], t))
        #         del_frame_list.append(t)
        # if del_frame_list:
        #     try:
        #         for t in del_frame_list:
        #             frame_detect_box.remove(t)
        #     except:
        #         pass
        if not frame_detect_box:
            # 如果未检测到box，初始化一个测试box
            frame_detect_box = [[1, 1, 2, 2]]
        try:
            self.trackers_C = self.tracker.match(frame_detect_box, state="C")
            self.trackers_U = self.tracker.match(frame_detect_box, state="U")
            self.trackers_M = self.tracker.match(frame_detect_box, state="M")

            # 如果预测框与检测框大于阈值，用检测框代替预测框
            for i in range(len(self.trackers_C)):
                most_similar = self.find_most_roi(self.trackers_C[i], frame_detect_box)
                if most_similar:
                    self.trackers_C[i][:4] = most_similar[:4]
        except:
            log.logger.error(traceback.format_exc())
        section2_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info("检测的frame_detect_box为{}".format(frame_detect_box))
            log.logger.info(
                "第{}帧跟踪section2,预测模块处理耗时{:.6}，秒".format(self.count, section2_end - section1_end))

        # temp_dict = {item[-1]: (int(item[0]),int(item[1]),int(item[2]),int(item[3])) for item in self.trackers_C}
        # #去掉异常值（1，1，1，1）
        # if (1,1,2,2) in temp_dict.values():
        #     self.trackers_C = []
        # temp_dict1 = {item[-1]: (int(item[0]),int(item[1]),int(item[2]),int(item[3])) for item in self.trackers_C}
        # #去掉异常值（1，1，1，1）
        # if (1,1,2,2) in temp_dict1.values():
        #     self.trackers_C = []
        #
        # temp_dict2 = {item[-1]: (int(item[0]),int(item[1]),int(item[2]),int(item[3])) for item in self.trackers_U}
        # #去掉self.trackers_M异常值（1，1，1，1）
        # if (1,1,2,2) in temp_dict2.values():
        #     self.trackers_U = []
        #
        # temp_dict3 = {item[-1]: (int(item[0]),int(item[1]),int(item[2]),int(item[3])) for item in self.trackers_M}
        # #去掉self.trackers_M异常值（1，1，1，1）
        # if (1,1,2,2) in temp_dict3.values():
        #     self.trackers_M = []

        log.logger.debug("确定状态的列表为{}".format(self.trackers_C))
        log.logger.debug("不确定状态列表为{}".format(self.trackers_U))
        log.logger.debug("丢失目标的列表为{}".format(self.trackers_M))
        log.logger.debug("存放的目标列表为{}".format(self.object_list))
        log.logger.debug("self.box_count_confirm为{}".format(self.box_count_confirm))

        ##对丢失的目标进行预测，然后进行替换，因为丢失的目标box会有问题，要确保船长不变，航向不变,不清楚为啥未确认的目标会丢失目标，导致程序报错，因此加上try:except
        # if len(self.trackers_M):
        #     try:
        #         for i in range(len(self.trackers_M)):
        #             id = int(self.trackers_M[i][-1])
        #
        #             predict_box = self.predict_missobject(id,self.box_count_confirm[str(id)])
        #             if predict_box:
        #                 self.trackers_M[i][:4] = predict_box
        #     except:
        #         pass
        ####将丢失目标添加到确认目标里
        # if len(self.trackers_C) and len(self.trackers_M):
        #     self.trackers_C = np.concatenate((self.trackers_C,self.trackers_M), axis=0)
        #     log.logger.debug("确定状态的列表为{}".format(self.trackers_C))
        section3_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧跟踪section3处理耗时{:.6}，秒".format(self.count, section3_end - section2_end))
        original_frame = copy.copy(frame)
        # 视频流展示用（内部）
        video_push_dict = {}
        # 视频流展示用（外部，给前端用）
        video_push_list = []
        push_moudle_dict = {}
        uncertain_object_list = []

        # 绘画检测框
        if int(self.init['disp_mode']) == 1:
            cv2.rectangle(self.frame, (int(self.object_confirm_roi[0]), int(self.object_confirm_roi[1])),
                          (int(self.object_confirm_roi[2]), int(self.object_confirm_roi[3])), (0, 0, 255), thickness=1)
            cv2.putText(self.frame, "detect_box", (int(self.object_confirm_roi[2]),
                                                   int(self.object_confirm_roi[3]) + 7), 0, 0.5, (0, 0, 255), 1)

        ##判断是否有匹配的mmsi目标
        ais_pick_id_mmsi = {value: key for key, value in self.ais_pick.items()}
        if ais_pick_id_mmsi:
            log.logger.debug("ais_pick_id_mmsi为{}".format(ais_pick_id_mmsi))
        section4_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧跟踪section4处理耗时{:.6}，秒".format(self.count, section4_end - section3_end))
        # 数据推送判断,需要放在删除不需要匹配的ais信息之前,以及ais更新之前
        self.put_top_box()
        section5_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧跟踪section5,put_box模块处理耗时{:.6}，秒".format(self.count, section5_end - section4_end))

        # if aisShipName:
        #     text_bg_x1 = 20
        #     text_bg_y1 = 670
        #     text_bg_x2 = text_bg_x1 + 700
        #     text_bg_y2 = 710
        # else:
        #     text_bg_x1 = 20
        #     text_bg_y1 = 670
        #     text_bg_x2 = text_bg_x1 + 500
        #     text_bg_y2 = 710

        # fill_color = (255, 230, 0)
        #
        # blk = np.zeros(self.frame.shape, np.uint8)
        #
        # cv2.rectangle(blk, (text_bg_x1, text_bg_y1), (text_bg_x2, text_bg_y2), fill_color,
        #               -1)  # 注意在 blk的基础上进行绘制；
        # saveframe = cv2.addWeighted(saveframe, 1.0, blk, 0.67, 1)

        # 给内部的数据推送
        uncertain_box = []
        # 确定的目标画框
        for i in self.trackers_C:
            # 中心点
            center_point_x = int((i[0] + i[2]) / 2)
            # center_point_y = int((i[1] + i[3]) / 2)
            # 以底边缘中心点进行计算
            center_point_y = i[3]

            # 如果目标的中心点在检测框里，进行以下操作
            if self.object_confirm_roi[0] < center_point_x and center_point_x < self.object_confirm_roi[2] and \
                    self.object_confirm_roi[1] < center_point_y and center_point_y < self.object_confirm_roi[3]:
                # 如果不是新目标，pass；如果是新目标，则进行append操作
                if int(i[4]) in self.object_list:
                    log.logger.debug("目标id：{} 已在self.object_list列表里".format(int(i[4])))
                else:
                    log.logger.debug("目标id：{} 不在self.object_list列表里，添加到列表".format(int(i[4])))
                    self.object_list.append(int(i[4]))
            else:
                log.logger.debug(
                    "目标中心点{},{}不在self.object_confirm_roi:{}范围内".format(center_point_x, center_point_y,
                                                                       self.object_confirm_roi))

            # 蓝色（未融合ais情况下）
            cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (255, 0, 0), thickness=1)

            # print([int(i) for i in frame_box_dict["detBox"]])

            # video_push_dict[str(i[4])] = {
            #     "aisShipName": frame_box_dict["aisShipName"],
            #     "aisMmsi": frame_box_dict["aisMmsi"],
            #     "snapDistance": frame_box_dict["snapDistance"],
            #     "currentState": frame_box_dict["currentState"],
            #     "detBox": [int(i) for i in frame_box_dict["detBox"]]}

            # try:
            # 画目标点，如果目标在检测框里，目标id初始为1，向上增加，
            if int(i[4]) in self.object_list:
                id = str(self.object_list.index(int(i[4])) + 1)
                # 从推送数据实时获取数据
                result = self.r.hget(self.snap_task_key_name, str(id))
                if not result:
                    # 如果数据获取为空，尝试用
                    result = self.r.hget(self.snap_task_key_name, str(id) + '.' + str(id))
                if result:
                    frame_box_dict = json.loads(result)
                if frame_box_dict["detBox"]:
                    video_push_dict[id] = {
                        "aisShipName": frame_box_dict["aisShipName"],
                        "aisMmsi": frame_box_dict["aisMmsi"],
                        "snapDistance": frame_box_dict["snapDistance"],
                        "currentState": frame_box_dict["currentState"],
                        "aisShipSpd": frame_box_dict["aisShipSpd"],
                        "islyingDown": frame_box_dict["islyingDown"],
                        "isReverse": frame_box_dict["isReverse"],
                        "isOverTaking": frame_box_dict["isOverTaking"],
                        "detBox": [int(i) for i in frame_box_dict["detBox"]]}
                # redis获取异常，人工赋值，保障框正常
                else:
                    video_push_dict[id] = {
                        "aisShipName": "",
                        "aisMmsi": 0,
                        "snapDistance": 0,
                        "currentState": 0,
                        "aisShipSpd": -1,
                        "islyingDown": -1,
                        "isReverse": -1,
                        "isOverTaking": -1,
                        "detBox": [int(i[0]), int(i[1]), int(i[2]), int(i[3])]}

                # 推送至前端展示用
                if frame_box_dict["aisMmsi"]:
                    video_push_list.append({
                        "id": id,
                        "sn": frame_box_dict["aisShipName"],
                        "m": frame_box_dict["aisMmsi"],
                        "p": [int(i) for i in frame_box_dict["detBox"]],
                        "dws": 0,
                        "dl": 0,
                    })

                # 判断船舶推送列表是否为空，并且确定的框的id是否在字典里，如果在，展示信息
                # if self.object_dict_push and str(self.object_list.index(int(i[4])) + 1) in self.object_dict_push.keys() --》有异常str(self.object_list.index(int(i[4])) + 1) not in self.no_push_id_dict.keys():
                if self.object_dict_push and str(
                        self.object_list.index(int(i[4])) + 1) in self.object_dict_push.keys() and str(
                    self.object_list.index(int(i[4])) + 1) not in self.no_push_id_dict.keys():
                    try:
                        fill_color = (255, 230, 0)
                        # fill_color = (255, 0, 0)

                        blk = np.zeros(self.frame.shape, np.uint8)

                        cv2.rectangle(blk, (int(i[0]) - 20, int(i[1]) - 40), (int(i[0]) + 80, int(i[1]) + 40),
                                      fill_color,
                                      -1)  # 注意在 blk的基础上进行绘制；
                        self.frame = cv2.addWeighted(self.frame, 1.0, blk, 0.67, 1)

                        ##如果ais匹配成功，变成绿色框
                        if str(self.object_list.index(int(i[4])) + 1) in ais_pick_id_mmsi.keys():
                            mmsi = str(ais_pick_id_mmsi[str(self.object_list.index(int(i[4])) + 1)])
                            # print('mmsi',mmsi)

                            # 判断mmsi是否在self.ais_point_dict_copy，过一段时间mmsi未更新将被删除
                            # if str(mmsi) in self.ais_point_dict_copy.keys():
                            # shipname = self.ais_point_dict_copy[int(mmsi)][max((self.ais_point_dict_copy[int(mmsi)].keys()))]["shipname"]
                            try:
                                shipname = self.dict_mmsi_shipname[str(mmsi)][1]
                            except:
                                log.logger.error(traceback.format_exc())
                                shipname = ''

                                # 再次保障框变成绿色框，每次迭代时会初始化为蓝色
                            cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (0, 255, 0),
                                          thickness=1)

                            self.frame = cv2ImgAddText(self.frame,
                                                       "id={},mmsi={},shipname={}".format(id, mmsi, shipname),
                                                       int(i[0]), int(i[1]) - 14, (0, 0, 0), 18)
                            # else:
                            #     log.logger.debug("mmsi{}不在self.ais_point_dict_copy，由于长时间未更新，被删除".format(mmsi))
                            #     #再次保障框变成绿色框，每次迭代时会初始化为蓝色
                            #     cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (0, 255, 0), thickness=1)
                            #     self.frame = cv2ImgAddText(self.frame, "id={},mmsi={}".format(id,mmsi),  int(i[0]), int(i[1]) - 14, (0, 255, 0), 14)

                        else:
                            cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (0, 255, 0),
                                          thickness=1)
                            self.frame = cv2ImgAddText(self.frame, "id = {}".format(id), int(i[0]), int(i[1]) - 14,
                                                       (0, 0, 0), 18)
                    except:
                        log.logger.error(traceback.format_exc())
            else:
                log.logger.debug("原始目标{}不在self.object_list里面".format(i[4]))
                # 如果原始目标不在self.object_list里面，当成未确认目标
                uncertain_box.append([int(i[0]), int(i[1]), int(i[2]), int(i[3])])

                # print([int(i) for i in frame_box_dict["detBox"]])
                # if frame_box_dict["detBox"] and  frame_box_dict["currentState"]:

                # video_push_dict[str(i[4])] = {
                #     "aisShipName": frame_box_dict["aisShipName"],
                #     "aisMmsi": frame_box_dict["aisMmsi"],
                #     "snapDistance": frame_box_dict["snapDistance"],
                #     "currentState": frame_box_dict["currentState"],
                #     # "detBox": [int(i) for i in frame_box_dict["detBox"]]}
                #     "detBox": [int(i[0]), int(i[1]), int(i[2]), int(i[3])]}

                # cv2.putText(self.frame, "id = {}".format(id),(int(i[0]), int(i[1]) - 14), 0, 0.5, (0, 255, 0), 1)
            # except:
            #     log.logger.debug(traceback)

        # 未确定的目标画框（不打标签）

        for i in self.trackers_U:
            cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (0, 250, 255), thickness=2)
            uncertain_box.append([int(i[0]), int(i[1]), int(i[2]), int(i[3])])

        video_push_dict["-1"] = uncertain_box

        # 跟踪丢失的目标画框,可以去掉，因为目前都把丢失的目标存放到确认目标里
        for i in self.trackers_M:
            # log.logger.debug("id：{}目标丢失".format(str(self.object_list.index(int(i[4])) + 1)))
            # cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (0, 0, 255), thickness=1)
            if self.object_dict_push and (int(i[4])) in self.object_list and str(
                    self.object_list.index(int(i[4])) + 1) in self.object_dict_push.keys():
                # box数据推送
                try:
                    id = str(self.object_list.index(int(i[4])) + 1)
                    result = self.r.hget(self.snap_task_key_name, str(id))
                    if result:
                        frame_box_dict = json.loads(result)
                        # if frame_box_dict["detBox"]:
                        video_push_dict[str(self.object_list.index(int(i[4])) + 1)] = {
                            "aisShipName": frame_box_dict["aisShipName"],
                            "aisMmsi": frame_box_dict["aisMmsi"],
                            "snapDistance": frame_box_dict["snapDistance"],
                            "currentState": frame_box_dict["currentState"],
                            "aisShipSpd": frame_box_dict["aisShipSpd"],
                            "islyingDown": frame_box_dict["islyingDown"],
                            "isReverse": frame_box_dict["isReverse"],
                            "isOverTaking": frame_box_dict["isOverTaking"],
                            "detBox": [int(i[0]), int(i[1]), int(i[2]), int(i[3])]}
                    ##如果ais匹配成功，变成绿色框
                    if str(self.object_list.index(int(i[4])) + 1) in ais_pick_id_mmsi.keys():
                        mmsi = str(ais_pick_id_mmsi[str(self.object_list.index(int(i[4])) + 1)])
                        # shipname = self.ais_point_dict_copy[int(mmsi)][max((self.ais_point_dict_copy[int(mmsi)].keys()))]["shipname"]
                        # shipname = self.ais_point_dict_copy[int(mmsi)][max((self.ais_point_dict_copy[int(mmsi)].keys()))]["shipname"]
                        try:
                            shipname = self.dict_mmsi_shipname[str(mmsi)][1]
                        except:
                            log.logger.error(traceback.format_exc())
                            shipname = ''
                        self.frame = cv2ImgAddText(self.frame, "id={},mmsi={},shipname ={}".format(
                            str(self.object_list.index(int(i[4])) + 1), mmsi, shipname), int(i[0]),
                                                   int(i[1]) - 14, (0, 255, 0), 14)
                    else:
                        # cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (0, 255, 0),thickness=1)
                        cv2.rectangle(self.frame, (int(i[0]), int(i[1])), (int(i[2]), int(i[3])), (255, 255, 0),
                                      thickness=1)
                        self.frame = cv2ImgAddText(self.frame,
                                                   "id={}".format(str(self.object_list.index(int(i[4])) + 1)),
                                                   int(i[0]), int(i[1]) - 14, (0, 255, 0), 14)


                except:
                    log.logger.error(traceback.format_exc())

        # 数据推送判断,需要放在删除不需要匹配的ais信息之前,以及ais更新之前
        # self.put_top_box()

        # 画ais信息框
        # self.ais_point_dict_copy1 = ais_point_dict.copy()
        # 去重
        self.ais_point_dict_copy = pick_top1_ais_dict(ais_point_dict)
        log.logger.debug("去重后的ais数据为{}".format(self.ais_point_dict_copy))
        # #需要删除的key
        keys_to_remove = []
        for key, value in self.ais_point_dict_copy.items():
            updtime = str(datetime.datetime.now()).replace("-", "").replace(":", "").replace(" ", "")[0:14]
            keymax = max(self.ais_point_dict_copy[key].keys(), key=int)
            delt_time = (datetime.datetime.strptime(updtime, '%Y%m%d%H%M%S') - datetime.datetime.strptime(keymax,
                                                                                                          '%Y%m%d%H%M%S')).seconds
            if delt_time > 300:
                keys_to_remove.append(key)
                # log.logger.debug("ais{}在120秒内未更新，删掉该ais".format(key))
                # self.ais_point_dict_copy.pop(key)
        for key in keys_to_remove:
            log.logger.debug("ais{}在120秒内未更新，删掉该ais".format(key))
            del self.ais_point_dict_copy[key]

        # 20230313 取消删除不需要匹配的ais信息
        # if int(self.init['disp_mode']) == 1:
        # try:
        if self.ais_point_dict_copy.items:

            for key, value in self.ais_point_dict_copy.items():
                # 已经剔除的ais不显示（已经匹配上的ais）
                if key not in self.pop_ais:
                    cv2.circle(self.frame, (
                        int(self.ais_point_dict_copy[key][max((self.ais_point_dict_copy[key].keys()))]["point"][0]),
                        int(self.ais_point_dict_copy[key][max((self.ais_point_dict_copy[key].keys()))]["point"][1])), 3,
                               (0, 255, 0), -1)
                    cv2.putText(self.frame, str(key), (
                        int(self.ais_point_dict_copy[key][max((self.ais_point_dict_copy[key].keys()))]["point"][0]),
                        int(self.ais_point_dict_copy[key][max((self.ais_point_dict_copy[key].keys()))]["point"][
                                1]) - 7), 0, 0.5, (0, 255, 0), 1)
        # except:
        #     log.logger.error(traceback.format_exc())

        section6_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧跟踪section6，目标画框显示模块处理耗时{:.6}，秒".format(self.count, section6_end - section5_end))
        # 更新ais融合(要放在数据推送后面)
        ais_imerge_start = time.time()  # 结束时间
        self.ais_imerge()
        ais_imerge_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info("第{}帧section7,ais融合模块耗时{:.6}，秒".format(self.count, ais_imerge_end - ais_imerge_start))
        # if self.count - self.ais_imerge_count > 48:
        #
        #     self.ais_imerge()
        #     self.ais_imerge_count = self.count
        # else:
        #     self.ais_imerge_count += 1

        # 更新box_count字典
        update_box_count_start = time.time()  # 结束时间
        self.update_box_count()
        self.updata_box_count_confirm()
        self.update_pushvideo()
        # 更新停泊船字典
        self.update_no_push_id_dict()
        update_box_count_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧section8,update_box更新耗时{:.6}，秒".format(self.count, update_box_count_end - update_box_count_start))
        if platform.system() == 'Windows':
            cv2.namedWindow("Frame", cv2.WINDOW_NORMAL)
            cv2.imshow("Frame", self.frame)
            cv2.waitKey(10)

        redis_push_outside_start = time.time()  # 开始时间
        # self.r.hset(self.res_task_key_name_box, str(self.count),json.dumps(video_push_dict, ensure_ascii=False))
        # cv2.imencode('.jpg', self.frame)[1].tofile(os.path.join())
        if int(self.init['frame_box_put_activate']) == 1:
            # 开启数据推送
            retval, buffer = cv2.imencode('.jpg', original_frame)
            jpg_as_text = base64.b64encode(buffer).decode()
            result = {
                "frame_detect_box": video_push_dict,
                "jpg_as_text": jpg_as_text
            }
            log.logger.debug("推送到内部的redis数据为：{}".format(result["frame_detect_box"]))
            self.r.hset(self.res_task_key_name_frame, str(1), json.dumps(result))

        if self.init['videoPushOutside_activate'] == 1:
            try:
                self.r_outside.hset(self.init['videoPushOutside_res_task_key_name'], str(1),
                                    json.dumps(video_push_list))
                if self.count % (self.init['frame_rate'] * 10) == 0:
                    log.logger.debug("推送到videoPushOutside数据为：{}".format(json.dumps(video_push_list)))
                self.r_outside_temp.hset('ImgProc-list-test-quanjing', str(1), json.dumps(video_push_list))
            except:
                log.logger.error(traceback.format_exc())
        redis_push_outside_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info("第{}帧section9,redis外部对接模块耗时{:.6}，秒".format(self.count,
                                                                       redis_push_outside_end - redis_push_outside_start))

        self.pusher.push_video(self.frame, self.init['video_save_path'])

        push_vide_end = time.time()  # 结束时间
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧section10,视频流推送模块耗时{:.6}，秒".format(self.count, push_vide_end - redis_push_outside_end))

    def predict_missobject(self, id, detection_boxes):
        if int(id) in self.object_list:
            id = str(self.object_list.index(int(id)) + 1)
        # log.logger.debug("id:{}目标丢失，进行预测，接收到的box为{}".format(id, detection_boxes))

        # 对键进行排序
        sorted_keys = sorted(detection_boxes, key=lambda x: int(x))

        # 找到左边界的最小值和最大值
        min_key = sorted_keys[0]
        max_key = sorted_keys[-1]

        min_value = detection_boxes[min_key][0]
        max_value = detection_boxes[max_key][0]

        # 如果最小值在key中间，最小值为拐点
        for i in range(1, len(sorted_keys) - 1):
            if detection_boxes[sorted_keys[i]][0] < min_value:
                min_key = sorted_keys[i]
                min_value = detection_boxes[sorted_keys[i]][0]

        # 如果最大值在key中间，最大值为拐点
        for i in range(1, len(sorted_keys) - 1):
            if detection_boxes[sorted_keys[i]][0] > max_value:
                max_key = sorted_keys[i]
                max_value = detection_boxes[sorted_keys[i]][0]

        # 判断最小值或最大值是否是拐点
        if min_key != sorted_keys[0] and min_key != sorted_keys[-1]:
            inflection_point_key = min_key
            inflection_point_value = min_value
        elif max_key != sorted_keys[0] and max_key != sorted_keys[-1]:
            inflection_point_key = max_key
            inflection_point_value = max_value
        else:
            inflection_point_key = None
            inflection_point_value = None
        # 如果存在拐点
        if inflection_point_key:
            # 对键进行排序
            # sorted_data = sorted(detection_boxes.items(), key=lambda x: int(x[0]))
            # 取出第一个元素和拐点元素
            smallest_first_roi = detection_boxes[sorted_keys[0]]

            smallest_inflection_point_roi = detection_boxes[inflection_point_key]
            smallest_last_roi = detection_boxes[sorted_keys[-1]]

            shiplen_pix = int(float(smallest_first_roi[2]) - float(smallest_first_roi[0]))
            shipspd_pix = int(float(smallest_inflection_point_roi[0]) - float(smallest_first_roi[0])) / (
                    sorted_keys.index(inflection_point_key) - sorted_keys.index(sorted_keys[0]))
            log.logger.debug("smallest_last_roi为{}，smallest_first_roi为{}".format(smallest_last_roi, smallest_first_roi))
            log.logger.debug(
                "id:{}目标丢失，进行预测，接收到的box，拐点，船长，船像素速度分别{}，{}，{}，为{}".format(id, detection_boxes, inflection_point_key,
                                                                          shiplen_pix, shipspd_pix))
            ##预测只在画面中央，边界不进行预测
            if all(int(element) > 100 for element in smallest_first_roi) and all(
                    int(element) < 1000 for element in smallest_first_roi) and all(
                int(element) > 0 for element in smallest_last_roi) and all(
                int(element) < 1000 for element in smallest_last_roi):
                # if int(smallest_last_roi[0]) > 100 or int(smallest_last_roi[2]) < 1000:
                xmin = int(smallest_inflection_point_roi[0]) + (
                        sorted_keys.index(sorted_keys[-1]) - sorted_keys.index(inflection_point_key)) * int(
                    shipspd_pix)
                ymin = int(smallest_inflection_point_roi[1])
                xmax = xmin + shiplen_pix
                ymax = int(smallest_inflection_point_roi[3])

                if inflection_point_key:
                    for key in sorted_keys:
                        if int(key) > int(inflection_point_key):
                            detection_boxes[str(key)] = [int(smallest_inflection_point_roi[0]) + (
                                    sorted_keys.index(key) - sorted_keys.index(inflection_point_key)) * int(
                                shipspd_pix),
                                                         int(smallest_inflection_point_roi[1]),
                                                         int(smallest_inflection_point_roi[0]) + (
                                                                 sorted_keys.index(key) - sorted_keys.index(
                                                             inflection_point_key)) * int(
                                                             shipspd_pix) + shiplen_pix,
                                                         int(smallest_inflection_point_roi[3])]

                predict_box = (xmin, ymin, xmax, ymax)
                log.logger.debug(
                    "id:{}目标丢失，进行预测，修正后的box为{}预测的box为{}".format(id, detection_boxes, predict_box))
                return predict_box
            # else:
            #     return None
        else:
            return None

    def calculate_iou(self, box1, box2):
        # 将边界框表示为 (x, y, w, h) 格式，其中 (x, y) 是左上角坐标，(w, h) 是宽度和高度
        x1 = int(box1[0])
        y1 = int(box1[1])
        w1 = int(box1[2]) - int(box1[0])
        h1 = int(box1[3]) - int(box1[1])

        x2 = int(box2[0])
        y2 = int(box2[1])
        w2 = int(box2[2]) - int(box2[0])
        h2 = int(box2[3]) - int(box2[1])

        # x1, y1, w1, h1 = box1
        # x2, y2, w2, h2 = box2

        # 计算交集的边界框坐标
        xmin = max(x1, x2)
        ymin = max(y1, y2)
        xmax = min(x1 + w1, x2 + w2)
        ymax = min(y1 + h1, y2 + h2)

        # 计算交集的面积
        intersection_area = max(0, xmax - xmin + 1) * max(0, ymax - ymin + 1)

        # 计算并集的面积
        box1_area = w1 * h1
        box2_area = w2 * h2
        union_area = box1_area + box2_area - intersection_area

        # 计算交并比
        iou = intersection_area / union_area

        return iou

    # 计算box与列表box中的最大roi的box
    def find_most_roi(self, box, frame_list):
        max_similarity = -1
        most_similar_num = None
        for i in frame_list:
            similarity = self.calculate_iou(box, i)  # 自定义计算相似度的函数
            if similarity > max_similarity:
                max_similarity = similarity
                most_similar_num = i
        # return most_similar_num, max_similarity
        if max_similarity > 0.6:
            return most_similar_num
        # if max_similarity > 0.6:
        #     return most_similar_num, max_similarity
        # else:
        #     return None, None

    def detect_trend_list(self, boxes):
        differences = []

        for i in range(1, len(boxes)):
            difference = boxes[i] - boxes[i - 1]
            differences.append(difference)

        positive_count = 0
        negative_count = 0

        for diff in differences:
            if diff > 0:
                positive_count += 1
            elif diff < 0:
                negative_count += 1

        if positive_count > negative_count:
            trend = "变大"
        elif positive_count < negative_count:
            trend = "变小"
        else:
            trend = "无明显变化"

        return trend

    def detect_trend_box(self, box_dict):

        w_changes = []

        timestamps = sorted(box_dict.keys())  # 对时间戳进行排序

        for i in range(1, len(timestamps)):
            curr_box = box_dict[timestamps[i]]
            prev_box = box_dict[timestamps[i - 1]]

            curr_w = curr_box[2]
            prev_w = prev_box[2]

            w_change = abs(curr_w - prev_w)

            w_changes.append(w_change)

        return self.detect_trend_list(w_changes)

    def detect_occlusion(self, box_dict, threshold):
        consecutive_decreases_left = 0  # 连续左侧遮挡次数
        consecutive_decreases_right = 0  # 连续右侧遮挡次数
        timestamps = sorted(box_dict.keys())  # 对时间戳进行排序

        if len(timestamps) < 2:
            raise ValueError("时间戳数量不足，无法进行比较和判断")
        try:
            for i in range(1, len(timestamps)):
                curr_box = box_dict[timestamps[i]]
                prev_box = box_dict[timestamps[i - 1]]

                curr_x = curr_box[0]
                prev_x = prev_box[0]

                x_change = curr_x - prev_x

                # 统计连续左侧遮挡和右侧遮挡的次数
                if x_change > 0:
                    consecutive_decreases_left += 1
                    consecutive_decreases_right = 0
                elif x_change < 0:
                    consecutive_decreases_right += 1
                    consecutive_decreases_left = 0
                else:
                    consecutive_decreases_left = 0
                    consecutive_decreases_right = 0

                if consecutive_decreases_left >= threshold:
                    return "左侧被遮挡"
                elif consecutive_decreases_right >= threshold:
                    return "右侧被遮挡"

        except KeyError:
            raise ValueError("检测框数据不完整或缺少关键字段")

        return "未被遮挡"
        # positive_count = 0
        # negative_count = 0
        #
        # for w_change in w_changes:
        #     if w_change > 0:
        #         positive_count += 1
        #     elif w_change < 0:
        #         negative_count += 1
        #
        # w_trend = "变大" if positive_count > negative_count else "变小" if positive_count < negative_count else "无明显变化"
        #
        # return w_trend

    # 船舶推送需要从画面左右俩侧进入、然后再确认目标的过程。如果全程是在画面中央确认目标，则有可能是停泊船（遮挡船），这些船舶数据也不推送。

    def pushship_confirm(self, id, id_box):
        if self.init["park_ship_activate"] == 0:
            return True
        else:
            log.logger.debug("判断id：{}的船舶轨迹是否在停泊船字典里。轨迹id_box为{}".format(id, id_box))

            min_x = 1920
            min_y = 1080
            max_x = 0
            max_y = 0
            max_iou = 0
            max_key = None
            for _, box in id_box.items():
                min_x = min(min_x, box[0])
                min_y = min(min_y, box[1])
                max_x = max(max_x, box[2])
                max_y = max(max_y, box[3])
            big_box = [min_x, min_y, max_x, max_y]
            if self.no_push_id_dict:
                for key, value in self.no_push_id_dict.items():

                    iou = self.calculate_iou(big_box, value)
                    if iou > max_iou:
                        max_iou = iou
                        max_key = key
                if max_key:
                    log.logger.debug("id：{},id_box{},与停泊船列表最大相似度为{}，value为{}".format(id, big_box, max_iou,
                                                                                     self.no_push_id_dict[max_key]))
                    if max_iou > 0.7:
                        log.logger.debug("最大交并比大于0.7，id:{}为停泊船".format(id))
                        return False
                    else:
                        return True
                else:
                    return True
            else:
                return True

    def judge_overtaking(self, id, box):
        # 每次判断目标id是否追越，取5个点判断。
        sorted_id_box = {k: v for i, (k, v) in enumerate(sorted(box.items())) if i % (len(box) // 5) == 0} if len(
            box) >= 5 else box
        # 通过5个点进行判断
        id_head = self.judge_heading(sorted_id_box)

        log.logger.debug("sorted_id_box:{}".format(sorted_id_box))
        filter_dict = {}
        log.logger.debug("self.box_count_confirm:{}".format(self.box_count_confirm))
        # 船舶在给定的roi内才进行检测
        sorted_id_box = {key: value for key, value in sorted_id_box.items() if
                         value[0] >= self.init['ship_overtaking_roi'][0] and value[2] <=
                         self.init['ship_overtaking_roi'][2]}
        if sorted_id_box:

            for key, value in self.box_count_confirm.items():
                # 判断航向，追越只关注同一航向的
                pre_heading = self.judge_heading(self.box_count_confirm[key])
                try:
                    if pre_heading == id_head and int(self.object_list.index(int(key)) + 1) != int(id):
                        # 航向相同，且过滤本身的数据，将id对应的frame_id进行关联，判断追越针对的是同一帧的位置,并将符合要求的数据添加到filter_dict中
                        result = {k: v for k, v in sorted(self.box_count_confirm[key].items()) if
                                  k in sorted_id_box.keys()}
                        if result:
                            filter_dict[str(self.object_list.index(int(key)) + 1)] = result
                except:
                    pass
            log.logger.info("id:{},间隔取的5个box为{}，待进行计算的filter_dict为{}".format(id, sorted_id_box, filter_dict))
            if not filter_dict:
                log.logger.info("id：{}无追越情况".format(id))
            else:
                # 船舶在画面中是从左往右，判断xmax的值
                if int(id_head) > 0:
                    for key, value in filter_dict.items():
                        diff_list = [box[k][2] - filter_dict[key][k][2] for k in filter_dict[key].keys() if
                                     k in box.keys()]

                        # 如果diff_list长度大于3，去掉首尾数据（首尾数据在边缘处，可能有偏差，不满足差值递增要求）
                        diff_list = diff_list[1:-2] if len(diff_list) > 3 else diff_list

                        # 确保判断长度至少两个数据，才能判断是否追越
                        if len(diff_list) > 1:
                            is_increasing = all(x < y for x, y in zip(diff_list, diff_list[1:]))
                            if is_increasing:
                                log.logger.info("id：{}存在追越情况".format(id))
                                return True
                else:
                    # 船舶在画面中是从左往右，判断xmax的值
                    pass

        return False

    # 判断id的航向,输入:box：目标id的全流程轨迹
    # 输出：航向，第一个box，最后一个box
    def judge_heading(self, box):
        sorted_id_box = sorted(box.items(), key=lambda x: int(x[0]))
        first_key = sorted_id_box[0][0]
        last_key = sorted_id_box[-1][0]
        first_point = (box[str(first_key)][0] + box[str(first_key)][2]) / 2
        last_point = (box[str(last_key)][0] + box[str(last_key)][2]) / 2
        diff = 1 if last_point - first_point >= 0 else -1
        # return diff,box[str(first_key)],box[str(last_key)]
        return diff
        # print(id)
        # print(box)
        # print("self.box_count_confirm:{}".format(self.box_count_confirm))

    # 并行船舶检测
    def parallelship_detect(self, id, id_box):
        # 如果self.trackers_C长度<=1，说明画面里只有一艘船，非并行船舶
        # 如果self.trackers_C长度>1，先判断id的id_box的底边缘是否是self.trackers_C的最小值。如果不是，不用关注（底边缘小，说明是另一侧被折遮挡，目标丢失）
        # 如果id的id_box的底边缘为最小值，说明船舶会被遮挡，先计算两者的roi，如何有重叠，说明船舶被遮挡，如果没有重叠，说明还未被遮挡。
        # 如果被遮挡，进行返回False,预测新的box，修改self.trackers_C数据，进行数据推送

        # 并行船舶判断逻辑，如果船舶的长度变小（面积），并且self.trackers_C存在交集情况，则认为是并行船舶
        log.logger.debug("并行船舶判断：id:{},对应的id_box为{}".format(id, id_box))
        log.logger.debug("self.trackers_C：{}".format(self.trackers_C))
        log.logger.debug("self.box_count_confirm：{}".format(self.box_count_confirm))
        # 1. 如果self.trackers_C长度<=1，说明画面里只有一艘船，非并行船舶
        if len(self.trackers_C) <= 1:
            log.logger.debug(f"self.trackers_C：{self.trackers_C}长度为1,无并行船舶")
            return True
        # 2. 如果self.trackers_C长度>1,将trackers_C转换成字典的形式
        trackers_dict = {item[-1]: item[:-1] for item in self.trackers_C}
        # 获取最新帧数据
        max_id = max(id_box.keys(), key=int)  # 获取字典中最大的ID
        new_box = id_box[max_id]  # 根据最大ID获取对应的边界框
        # 3.通过交并比找到id_box的最新帧在self.trackers_C的目标
        target_id = None
        temp_iou = 0
        for key, value in trackers_dict.items():
            iou = self.calculate_iouV2(new_box, value)
            if iou > temp_iou:
                temp_iou = iou
                target_id = key
        # log.logger.info(f'通过交并比得出最新帧数据new_box{new_box}在self.trackers_C的目标ID为{target_id}')
        log.logger.debug("id{}最新帧{}在self.trackers_C的目标ID为{}".format(id, new_box, target_id))
        # 4. 判断目标最新帧数据地边缘（ymax）是否是self.trackers_C的最小值。如果不是(底边缘大)，不用关注（只关注底边缘小，底边缘小说明是另一侧被遮挡，目标丢失）
        new_ymax = new_box[3]
        for key, value in trackers_dict.items():
            if key != target_id:
                y = value[3]
                # 不是最小值，不会发生遮挡，直接返回True
                if y < new_ymax:
                    log.logger.debug(
                        f'经判断,最新帧底边缘{new_ymax}大于ID为{key}的地边缘{y},最新帧底边缘不是最小值,不用关注,返回True')
                    return True
        # 5. 如果id的id_box的底边缘为最小值，说明船舶会被遮挡，先通过两者的box，判断是否有重叠，说明船舶被遮挡，如果没有重叠，说明还未被遮挡。返回True
        for key, value in trackers_dict.items():
            if key != target_id:
                # if self.calculate_iouV2(value, new_box) > 0:
                if abs(value[2] - new_box[0]) < 100 or abs(value[0] - new_box[2]) < 100:
                    log.logger.debug(
                        "id{}最新帧{}与ID{}的box{}发生重叠(像素差小于100个像素),最新帧产生遮挡,开始预测最新帧数据".format(id, new_box, target_id, value))
                    # 删除id的最大key，该key对应的box是检测box，会有误差
                    # del id_box[max_id]
                    pre_frame, pre_box = self.correction_detBox(id_box)
                    log.logger.debug("id{}开始进行预测，输入为{}，预测结果为{}".format(id, id_box, pre_box))
                    trackers_dict[target_id] = pre_box
                    log.logger.debug(
                        "id{}最新帧预测结果为{}".format(id, pre_box))

                    log.logger.debug("id{}最新帧{}与ID{}的box{}发生重叠,最新帧产生遮挡,开始预测最新帧数据".format(id, new_box, target_id, value))
                    self.trackers_C = np.array(
                        [[xmin, ymin, xmax, ymax, int(item_id)] for item_id, [xmin, ymin, xmax, ymax] in
                         trackers_dict.items()])
                    log.logger.debug("更新后的self.trackers_C：{}".format(self.trackers_C))

                    # 更新并行船的id的self.box_count_confirm，如果某个key的值为[1.0, 1.0, 2.0, 2.0]，删除该key

                    # del_keys = [key1 for key1, value in  self.box_count_confirm[str(id)].items() if value == [1.0, 1.0, 2.0, 2.0]]
                    del_keys = [key1 for key1, value in id_box.items() if value == [1.0, 1.0, 2.0, 2.0]]
                    for k in del_keys:
                        # del self.box_count_confirm[str(id)][k]
                        del id_box[k]

                    log.logger.debug("进行最新帧预测，目标{}第{}预测结果为{}".format(id, max_id, pre_box))

                    id_box[max_id] = pre_box
                    # self.box_count_confirm[str(id)][max_id] = pre_box
                    log.logger.debug("更新后的self.box_count_confirm：{}".format(self.box_count_confirm))

                    # self.parallelship_dict[str(id)] = self.box_count_confirm[str(id)]
                    self.parallelship_dict[str(id)] = (id_box, target_id)
                    return False
        log.logger.debug(f'经判断,虽然最新帧底边缘为最小值{new_box},但目前未与其他船舶发生重叠,尚未被遮挡,返回True')
        return True

    def parallelship_datapush(self, det_box_dict):
        log.logger.debug(f'接收到的self.parallelship_dict并行船字典列表:{det_box_dict}')
        # 开始遍历字典中的数据
        for key, value in det_box_dict.copy().items():
            log.logger.debug(f'开始分析key为{key}:{value}的数据')
            if str(key) in self.parallelship_predict_count.keys():
                self.parallelship_predict_count[str(key)] = self.parallelship_predict_count[str(key)] + 1
            else:
                self.parallelship_predict_count[str(key)] = 1
            # 预测超过30次，则删除老的数据
            if self.parallelship_predict_count[key] > 30:
                # if len(value[0]) > 10:
                log.logger.debug(f'字典中的数据，key为{key}的数据长度已达阈值:{30}上限,该数据已被删除')
                det_box_dict.pop(key)
                self.parallelship_predict_count.pop(key)
            else:
                # 开始根据box值进行预测
                max_frame = int(max(value[0].keys(), key=int))
                min_frame = int(min(value[0].keys(), key=int))

                log.logger.debug('开始预测key为{}的第{}帧的数据为'.format(key, str(max_frame + self.init['frame_rate'])))
                x, y = value[0][str(min_frame)][0], value[0][str(min_frame)][1]
                x1, y1 = value[0][str(max_frame)][0], value[0][str(max_frame)][1]
                size = max_frame - min_frame
                offset_x = (x1 - x) / size
                offset_y = (y1 - y) / size
                predict_det_box = np.array([[
                    value[0][str(max_frame)][0] + offset_x * self.init['frame_rate'],
                    # value[0][str(max_frame)][1] + offset_y,
                    value[0][str(max_frame)][1],
                    value[0][str(max_frame)][2] + offset_x * self.init['frame_rate'],
                    value[0][str(max_frame)][3],
                    # value[0][str(max_frame)][3] + offset_y,
                    value[1]
                ]])
                # det_box_dict[key] =()
                det_box_dict[key][0][str(max_frame + self.init['frame_rate'])] = [
                    value[0][str(max_frame)][0] + offset_x,
                    # value[0][str(max_frame)][1] + offset_y,
                    value[0][str(max_frame)][1],
                    value[0][str(max_frame)][2] + offset_x,
                    value[0][str(max_frame)][3]
                    # value[0][str(max_frame)][3] + offset_y
                ]
                # log.logger.debug(f'经过预测,key为{key}的第{max_frame + 1}帧的数据为:{predict_det_box}')
                log.logger.debug(
                    '经过预测,key为{}的第{}帧的数据为{}:'.format(key, str(max_frame + self.init['frame_rate']), predict_det_box))
                # 获取新行的最后一位值
                new_value = predict_det_box[-1][-1]
                # 找到与新值匹配的行的索引
                if len(self.trackers_C):
                    log.logger.debug(f'self.trackers_C[:, -1]：{self.trackers_C[:, -1]},new_value：{new_value}')
                    matching_indices = np.where(self.trackers_C[:, -1] == new_value)[0]
                    if matching_indices.size > 0:
                        # 替换匹配行的第一个索引的内容
                        self.trackers_C[matching_indices[0]] = predict_det_box
                        log.logger.debug(f'self.trackers_C更新成功,新增后的trackers_C为:{self.trackers_C}')
                    else:
                        # 添加新行
                        self.trackers_C = np.vstack((self.trackers_C, predict_det_box))
                        log.logger.debug(f'self.trackers_C新增成功,新增后的trackers_C为:{self.trackers_C}')
                else:
                    self.trackers_C = predict_det_box
                    log.logger.debug(f'self.trackers_C新增成功,新增后的trackers_C为:{self.trackers_C}')

    def reverseship_detect(self, id, id_box):
        ##连续多次判断逆向，则定性为逆向
        direction = int(self.cal_ship_pix_speed(id, id_box))
        sorted_id_box = sorted(id_box.items(), key=lambda x: int(x[0]))
        is_inside_list = [box[1][3] > self.init['ship_reverse_roi'][0] for box in sorted_id_box]
        # 先判断id_box是否在逆向检测的roi内，如果在，在判断是否逆向行驶，如果不在，不判断
        result = True if is_inside_list.count(True) > is_inside_list.count(False) else False
        if result:
            # 船舶在roi里行驶，判断航向是否跟配置文件设置的一致，不报警，否则，报警
            if int(direction) * self.init['ship_direction'] >= 0:
                return False
            else:
                return True

    def calculate_iouV2(self, box1, box2):
        x1_min, y1_min, x1_max, y1_max = box1
        x2_min, y2_min, x2_max, y2_max = box2
        intersection_width = max(0, min(x1_max, x2_max) - max(x1_min, x2_min))
        intersection_height = max(0, min(y1_max, y2_max) - max(y1_min, y2_min))
        intersection_area = intersection_width * intersection_height
        box1_area = (x1_max - x1_min) * (y1_max - y1_min)
        box2_area = (x2_max - x2_min) * (y2_max - y2_min)
        iou = intersection_area / (box1_area + box2_area - intersection_area)
        return iou

    def correction_detBox(self, id_box):
        max_frame = int(max(id_box.keys(), key=int))
        min_frame = int(min(id_box.keys(), key=int))
        temp_frame = max_frame
        while True:
            temp_frame = temp_frame - 1
            if temp_frame < 0:
                log.logger.error(f'字典{id_box}中的帧数量较少，无法预测')
                return []
            elif str(temp_frame) in id_box:
                x, y = id_box[str(min_frame)][0], id_box[str(min_frame)][1]
                x1, y1 = id_box[str(temp_frame)][0], id_box[str(temp_frame)][1]
                size = temp_frame - min_frame
                offset_x = (x1 - x) / size
                # offset_x = (x1 - x) / size
                offset_y = (y1 - y) / size
                return max_frame, \
                       [
                           id_box[str(temp_frame)][0] + offset_x * (max_frame - temp_frame),
                           id_box[str(temp_frame)][1] + offset_y * (max_frame - temp_frame),
                           id_box[str(temp_frame)][2] + offset_x * (max_frame - temp_frame),
                           id_box[str(temp_frame)][3] + offset_y * (max_frame - temp_frame)
                       ]

    # 停泊船检测
    def parkship_detect(self, id, id_box):
        if self.init["park_ship_activate"] == 0:
            # 暂不开启
            self.no_push_id_dict = {}
            return True
        else:
            log.logger.debug("停泊船判断:id:{},对应的id_box为{}".format(id, id_box))
            log.logger.debug("停泊船列表为{}".format(self.no_push_id_dict))
            if len(id_box.keys()) > 3:
                # id_key_list = [*id_box]
                # 对id的key进行排序，排序规则为roi的xmin，去除最高值和最低值的key，去除异常值。
                # id_key_list = sorted(id_box.keys(), key=lambda x: id_box[x][0])[1:-1]
                id_key_list = sorted(id_box.keys(), key=lambda x: id_box[x][0])

                # 一段时间内船舶iou小于阈值，认为不是停泊船，进行数据推送.并且目标初始的box是从两边开始的。而不是从画面中间出现。目标第一个框和最后一个框交并比
                iou = self.calculate_iou(id_box[id_key_list[-1]], id_box[id_key_list[0]])
                id_box_first = id_box[id_key_list[0]]
                id_box_last = id_box[id_key_list[-1]]
                # 目标第一个框和最后一个框左边界差值
                left_abstract = abs(id_box_first[0] - id_box_last[0])
                # 目标第一个框和最后一个框右边界差值
                right_abstract = abs(id_box_first[2] - id_box_last[2])
                left_right_abstract = abs(id_box_first[0] - id_box_last[2])
                ship_len_pix = abs(id_box_first[2] - id_box_first[0])

                # 最后一个box和第一个box的左边界<1/10船长，最后一个box和第一个box的右边界<1/10船长，iou大于阈值
                if 10 * left_abstract < abs(id_box_first[2] - id_box_first[0]) and 10 * right_abstract < abs(
                        id_box_first[2] - id_box_first[0]) and float(iou) > 0.95 and (
                        abs(id_box_first[2] - id_box_first[0])) / (abs(id_box_first[3] - id_box_first[1])) > 3:
                    log.logger.debug(
                        "id为{}，第一个框和最后一个框分别为{}、{},左边界差值为{},右边界差值为{}，均小于第一个框的船舶长度的十分之一,初始box船长为{},第一个框和最后一个框的iou为{},first左边界和last右边界的差值为{},且船舶宽高比大于3，为停泊船，添加到停泊船字典里".format(
                            id, id_box_first, id_box_last, left_abstract, right_abstract, ship_len_pix, iou,
                            left_right_abstract))
                    self.no_push_id_dict[str(id)] = id_box_last
            return True

    def cal_ship_pix_speed(self, id, id_box):
        # 按照key值排序
        sorted_id_box = sorted(id_box.items(), key=lambda x: int(x[0]))
        # 将id_box进行修改，如果历史box太长的话，间隔取，实际上有5个box就可以计算航向了
        sorted_id_box = sorted_id_box[::len(sorted_id_box) // 5][:5] if len(sorted_id_box) > 5 else sorted_id_box

        median_xmin = 0
        median_xmax = 0
        # 计算相邻key的第一个元素差值并组成新的列表
        diff_list_xmin = []
        diff_list_xmax = []
        for i in range(1, len(sorted_id_box)):
            diff = int(sorted_id_box[i][1][0]) - int(sorted_id_box[i - 1][1][0])
            diff_list_xmin.append(diff)
        # 对列表进行排序
        log.logger.debug("id为{},历史box的xmin相邻差值列表为{}".format(id, diff_list_xmin))
        sorted_diff_list_xmin = sorted(diff_list_xmin)

        # 计算中位数
        n = len(sorted_diff_list_xmin)
        # 如果长度不为空
        if n:
            if n % 2 == 0:
                median_xmin = (sorted_diff_list_xmin[n // 2 - 1] + sorted_diff_list_xmin[n // 2]) / 2
            else:
                median_xmin = sorted_diff_list_xmin[n // 2]
            for i in range(1, len(sorted_id_box)):
                diff = int(sorted_id_box[i][1][2]) - int(sorted_id_box[i - 1][1][2])
                diff_list_xmax.append(diff)
            # 对列表进行排序
            log.logger.debug("id为{},历史box的xmax相邻差值列表为{}".format(id, diff_list_xmax))
            sorted_diff_list_xmax = sorted(diff_list_xmax)
            # 计算中位数
            n = len(sorted_diff_list_xmax)
            if n % 2 == 0:
                median_xmax = (sorted_diff_list_xmax[n // 2 - 1] + sorted_diff_list_xmax[n // 2]) / 2
            else:
                median_xmax = sorted_diff_list_xmax[n // 2]

            if median_xmax * median_xmin >= 0:
                result = median_xmax if abs(median_xmax) > abs(median_xmin) else median_xmin
                print("像素速度xmin,xmax分别为{}，{},最终选择{}".format(median_xmin, median_xmax, result))
                return int(result * 24 / (int(sorted_id_box[1][0]) - int(sorted_id_box[0][0])))
            else:
                if int(sorted_id_box[0][1][0]) > int(0.5 * self.frame.shape[1]):
                    return -1
                else:
                    return 1

            ##如果船舶左右边界移动的距离小于0.25个画面，通过
            # if abs(sorted_id_box[0][1][0] - sorted_id_box[-1][1][0]) < int(0.25 * self.frame.shape[1]) and abs(sorted_id_box[0][1][2] - sorted_id_box[-1][1][2]) < int(0.25 * self.frame.shape[1]):
            #     if int(sorted_id_box[0][1][0]) > int(0.5 * self.frame.shape[1]):
            #         return -1
            #     else:
            #         return 1
            # else:
            #     result = median_xmax if abs(median_xmax) > abs(median_xmin) else median_xmin
            #     log.logger.debug("像素速度xmin,xmax分别为{}，{},最终选择{}".format(median_xmin, median_xmax, result))
            #     return int(result * 24 / (int(sorted_id_box[1][0]) - int(sorted_id_box[0][0])))

            #
            # result = median_xmax if abs(median_xmax) > abs(median_xmin) else median_xmin
            # log.logger.debug("像素速度xmin,xmax分别为{}，{},最终选择{}".format(median_xmin,median_xmax,result))
            # return int(result * 24 / (int(sorted_id_box[1][0]) - int(sorted_id_box[0][0])))
        else:
            return 0

    def put_top_box(self):
        put_box_section1_start = time.time()
        ####并行船舶推送
        if int(self.init["parallelShipPredict"]) == 1:
            log.logger.debug("self.parallelship_dict并行船字典列表为{}".format(self.parallelship_dict))
            self.parallelship_datapush(self.parallelship_dict)
        else:
            log.logger.debug("并行船舶预测功能关闭")
        # 将每个点的任一刻box关联
        if len(self.trackers_U):
            # 获取目标二维列表的最后一列（id列表）eg [1,3,5,6,7]
            last_col_list_U = [int(t) for t in self.trackers_U[:, -1].tolist()]
            log.logger.debug("当前帧目标id列表为{}".format(last_col_list_U))
            log.logger.debug("当前帧不确定目标列表为{}".format(self.trackers_U))
            if last_col_list_U:
                # 对目标id列表进行循环判断，如果目标id已经在原列表中，则在原有基础字典上赋值，否则，添加新列表1
                for idx, i in enumerate(last_col_list_U):
                    # xmin>0开始计入(检测框大于若干个像素计算船长才会比较准)
                    # if float([float(t) for t in self.trackers_U[idx, :].tolist()][0]) >= float(self.init['push_set'][0]):
                    if str(i) in self.box_count.keys():
                        self.box_count[str(i)][str(self.count)] = [float(i) for i in
                                                                   self.trackers_U[idx, :].tolist()][0:-1]
                    else:
                        self.box_count[str(i)] = {
                            str(self.count): [float(i) for i in self.trackers_U[idx, :].tolist()][0:-1]
                        }
            # log.logger.debug("每个检测目标count_box列表为{}".format(self.box_count))
        put_box_section1_end = time.time()
        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
            log.logger.info(
                "第{}帧put_box_section_1耗时{:.6}，秒".format(self.count, put_box_section1_end - put_box_section1_start))
            log.logger.info("第{}帧self.object_list为{}".format(self.count, self.object_list))
            log.logger.debug("第{}帧self.box_count_confirm为{}".format(self.count, self.box_count_confirm))
        if self.object_list:
            if len(self.trackers_C):
                log.logger.debug("确认目标列表为{}".format(self.trackers_C))
                last_col_list_C = [int(t) for t in self.trackers_C[:, -1].tolist()]

                for idx, i in enumerate(last_col_list_C):
                    if str(i) in self.box_count_confirm.keys():
                        self.box_count_confirm[str(i)][str(self.count)] = [float(i) for i in
                                                                           self.trackers_C[idx, :].tolist()][0:-1]
                    else:
                        self.box_count_confirm[str(i)] = {
                            str(self.count): [float(i) for i in self.trackers_C[idx, :].tolist()][0:-1]
                        }
                log.logger.debug("每个检测目标count_box_confirm列表为{}".format(self.box_count_confirm))
                # 待推送列表为在self.list_left_to_right中并且索引不在已推送字典里，并且id要在确认目标中（解决异常点丢失）
                # push_list = [i for i in self.object_list if
                #              self.object_list.index(
                #                  i) not in self.object_dict_push.keys() and i in last_col_list_C and str(
                #                  i) in self.box_count.keys()]
                push_list = [i for i in self.object_list if
                             self.object_list.index(
                                 i) not in self.object_dict_push.keys() and i in last_col_list_C and str(
                                 i) in self.box_count.keys()]

                log.logger.debug("待推送目标id列表为{}".format(push_list))
                for i in push_list:
                    try:
                        if int(self.init["parallelShipPredict"]) == 1:
                            # 对每一条数据进行并行船舶确认，更新self.trackers_C字典
                            self.parallelship_detect(str(self.object_list.index(i) + 1), self.box_count_confirm[str(i)])
                            log.logger.debug("并行船舶字典为{}".format(self.parallelship_dict))

                        # 推送一条数据前，先将这个id添加到self.list_push列表，以防后续重复推送
                        # id_box_push = [float(t) for t in self.trackers_C[last_col_list_C.index(i), :].tolist()]
                        id_box_push = [int(t) for t in self.trackers_C[last_col_list_C.index(i), :].tolist()][0:-1]
                        if str(self.object_list.index(i) + 1) not in self.object_dict_push.keys():
                            log.logger.debug(
                                "待推送id{}id_box_push{}".format(str(self.object_list.index(i) + 1), id_box_push))
                        # log.logger.debug("待推送id{}id_box_push{}".format(i, id_box_push))
                        if id_box_push == [1.0, 1.0, 2.0, 2.0]:
                            continue
                        # id_gps_lgt, id_gps_lat = Ship_arguments_calculate(self.init).Com_Pt2GpsGet(id_box_push)
                        id_gps_lgt, id_gps_lat = self.ship_arguments_calculate.Com_Pt2GpsGet(id_box_push)
                        # log.logger.debug("待推送id{}经纬度为{},{}：".format(i, id_gps_lgt, id_gps_lat))
                        # ####将推送的id_box添加到id的历史box里
                        # self.box_count[str(i)][str(self.count)] = [float(i) for i in id_box_push[0:-1]]
                        id_box = self.box_count[str(i)]

                        id_key_list = [*id_box]
                        id_speedx_list = [
                            self.ship_speed_calculate.ship_speed_calculate(id_box[id_key_list[0]], id_box[key],
                                                                           id_key_list[0], i)[0] for key, value in
                            id_box.items()]
                        id_speedy_list = [
                            self.ship_speed_calculate.ship_speed_calculate(id_box[id_key_list[0]], id_box[key],
                                                                           id_key_list[0], i)[1] for key, value in
                            id_box.items()]
                        log.logger.debug(
                            "待推送id{}id_speedy_list列表为{}：".format(str(self.object_list.index(i) + 1), id_box))
                        id_speedx_list.sort()
                        id_speedy_list.sort()
                        id_speed_x = round(id_speedx_list[int(len(id_speedx_list) / 2)], 3)
                        id_speed_y = round(id_speedy_list[int(len(id_speedx_list) / 2)], 3)
                        id_speed = math.sqrt(id_speed_x ** 2 + id_speed_y ** 2)
                        log.logger.debug("待推送id{}x方向速度列表为{}：".format(str(self.object_list.index(i) + 1), id_speed_x))
                        log.logger.debug("待推送id{}最终速度为{}：".format(str(self.object_list.index(i) + 1), id_speed))
                        # id_shiplen_list = [self.ship_arguments_calculate.ship_size_calculate(id_box[key])[1] for key, value
                        #                    in id_box.items()]
                        # id_shiphm_list = [self.ship_arguments_calculate.ship_size_calculate(id_box[key])[0] for key, value
                        #                   in id_box.items()]
                        # id_shiplen_list.sort()
                        # id_shiphm_list.sort()

                        #####船舶中心点在画面中心
                        if int((int(id_box_push[0]) + int(id_box_push[2])) / 2) > int(
                                self.frame.shape[1]) / 2 - 50 and int(
                            (int(id_box_push[0]) + int(id_box_push[2])) / 2) < int(
                            self.frame.shape[1]) / 2 + 50:

                            id_shiphm, id_shiplen = self.ship_arguments_calculate.ship_size_calculate(id_box_push)
                            log.logger.debug(
                                "待推送id{}的box为{}，船舶长度列表为{}：".format(str(self.object_list.index(i) + 1), id_box_push,
                                                                   id_shiplen))
                        else:
                            id_shiphm = 0
                            id_shiplen = 0

                        # id_shiplen = id_shiplen_list[int(len(id_shiplen_list) / 2)]
                        # id_shiphm = id_shiphm_list[int(len(id_shiphm_list) / 2)]
                        # log.logger.debug("待推送id{}船舶长度列表为{}：".format(i, id_shiplen_list))
                        # log.logger.debug("待推送id{}最终船舶长度为{}：".format(i, id_shiplen))
                        # log.logger.debug("待推送id{}船舶高度列表为{}：".format(i, id_shiphm_list))
                        # log.logger.debug("待推送id{}最终船舶高度为{}：".format(i, id_shiphm))

                        # 像素移动距离（从船舶进行检测列表1/2处帧处为起始，当前帧为终止）
                        # id_pix_x = int(id_box[id_key_list[-1]][0] + id_box[id_key_list[-1]][2]) - int(id_box[id_key_list[len(id_key_list) // 2]][0] + id_box[id_key_list[0]][2])
                        rcgPixSpeed = self.cal_ship_pix_speed(str(self.object_list.index(i) + 1), id_box)
                        if self.init['ship_reverse_activate'] == 1:
                            is_reverse = 1 if self.reverseship_detect(str(self.object_list.index(i) + 1), id_box) else 0
                        else:
                            is_reverse = -1
                        # ##以防时间间隔相同
                        # time_inter = (int(id_key_list[-1]) - int(id_key_list[len(id_key_list) // 2])) / 24
                        # if time_inter != 0:
                        #     log.logger.debug("待推送id：{}像素移动{}间隔{}秒：".format(i, id_pix_x, time_inter))
                        #     rcgPixSpeed = round(id_pix_x / time_inter, 1)
                        # else:
                        #     rcgPixSpeed = 0

                        # 添加航向字段.每隔五个数取一个
                        # id_heading_list = [int((int(id_box[key][0]) + int(id_box[key][2])) / 2) for key, value in
                        #                    id_box.items()][0::5]
                        #
                        # log.logger.debug("待推送id{}的id_heading_list为{}".format(i,id_heading_list))
                        # # 如果航向列表大于11，则进行间隔挑选
                        # if len(id_heading_list) // 11:
                        #     pick_heading = [i for i in id_heading_list if
                        #                     id_heading_list.index(i) % (len(id_heading_list) // 11) == 0]
                        #     direction = bool(
                        #         [bool((pick_heading[i + 1] - pick_heading[i] >= 0)) for i in
                        #          range(len(pick_heading) - 1)].count(
                        #             True) - [bool((pick_heading[i + 1] - pick_heading[i] >= 0)) for i in
                        #                      range(len(pick_heading) - 1)].count(False) >= 0)
                        # else:
                        #     pick_heading = [i for i in id_heading_list]
                        #     direction = bool([bool((pick_heading[i + 1] - pick_heading[i] >= 0)) for i in
                        #                       range(len(pick_heading) - 1)].count(
                        #         True) - [bool((pick_heading[i + 1] - pick_heading[i] >= 0)) for i in
                        #                  range(len(pick_heading) - 1)].count(False) >= 0)

                        if int(rcgPixSpeed) >= 0:
                            # rcgDirection>0 船舶从左往右
                            rcgDirection = 1
                            id_speed = 1
                        else:
                            # rcgDirection < 0 船舶从右往左
                            rcgDirection = -1
                            id_speed = -1
                        # #像素速度从配置文件中获取
                        # if self.init["rcgPixSpeedMode"] == 1:
                        #     # 画面从左往右
                        #     if int(rcgDirection) > 0:
                        #         rcgPixSpeed = self.init["rcgPixSpeed"][0]
                        #     else:
                        #         # 画面从右往左
                        #         rcgPixSpeed = self.init["rcgPixSpeed"][1]

                        ship_camera_Distance = int(self.ship_arguments_calculate.ship_cam_distance(id_box_push))

                        # log.logger.debug("目标{}船舶离相机距离为{}：".format(i, ship_camera_Distance))
                        update_time = str(datetime.datetime.now()).replace("-", "/")[0:19]
                        ##判断是否有匹配的mmsi目标
                        aisMmsi = 0
                        heading = -1
                        aisShipName = ''
                        aisShipSpd = -1
                        try:
                            if str(self.object_list.index(i) + 1) in self.ais_pick.values():
                                ais_pick_id_mmsi = {value: key for key, value in self.ais_pick.items()}
                                aisMmsi = ais_pick_id_mmsi[str(self.object_list.index(i) + 1)]
                                try:
                                    heading = self.ais_point_dict_copy[int(aisMmsi)][
                                        sorted(self.ais_point_dict_copy[int(aisMmsi)].keys())[0]]['heading']
                                except:
                                    heading = 511
                                    # aisShipName = self.ais_point_dict_copy[int(aisMmsi)][sorted(self.ais_point_dict_copy[int(aisMmsi)].keys())[0]]['shipname']
                                # aisShipName = self.ais_point_dict_copy[int(aisMmsi)][sorted(self.ais_point_dict_copy[int(aisMmsi)].keys())[0]]['shipname']
                                try:
                                    aisShipName = self.dict_mmsi_shipname[str(aisMmsi)][1]
                                except:
                                    log.logger.error(traceback.format_exc())
                                try:
                                    aisShipSpd = self.ais_point_dict_copy[int(aisMmsi)][
                                        sorted(self.ais_point_dict_copy[int(aisMmsi)].keys())[0]]['speed']
                                except:
                                    log.logger.error(traceback.format_exc())


                        except:
                            log.logger.error(traceback.format_exc())

                        # 判断ais离船距离，有时候通过抓拍反算的距离不准,当匹配到ais的时候，通过ais经纬度计算距离，且只计算一次（实际获取到的ais经纬度，非预测）
                        ship_camera_Distance_Ais = 0
                        ship_camera_speed_Ais = 1
                        if aisMmsi:
                            try:
                                log.logger.debug("self.ais_point_dict_copy为{}：".format(self.ais_point_dict_copy))
                                if self.ais_point_dict_copy[int(aisMmsi)][
                                    sorted(self.ais_point_dict_copy[int(aisMmsi)].keys())[0]]['source'] == 'actual':
                                    ship_camera_Distance_Ais = int(self.ais_point_dict_copy[int(aisMmsi)][sorted(
                                        self.ais_point_dict_copy[int(aisMmsi)].keys())[0]]['distance'])
                            except:
                                log.logger.debug(traceback.format_exc())

                        # 每次id历史box列表只推送一次

                        if str(self.object_list.index(i) + 1) not in self.object_dict_push.keys():
                            # 第一次的时候进行视频流句柄加载
                            if self.init['ship_overtaking_activate'] == 1:
                                self.temppusher[str(self.object_list.index(i) + 1)] = VideoPusher(self.init)

                            log.logger.info("待推送id{}历史box列表为{}：".format(str(self.object_list.index(i) + 1), id_box))
                            log.logger.info(
                                "待推送id{}id_box_push{}".format(str(self.object_list.index(i) + 1), id_box_push))
                            log.logger.info(
                                "待推送id{}经纬度为{},{}：".format(str(self.object_list.index(i) + 1), id_gps_lgt, id_gps_lat))
                            # log.logger.info("待推送id{}船舶长度列表为{}：".format(i, id_shiplen_list))
                            log.logger.info("待推送id{}最终船舶长度为{}：".format(str(self.object_list.index(i) + 1), id_shiplen))
                            # log.logger.info("待推送id{}船舶高度列表为{}：".format(i, id_shiphm_list))
                            log.logger.info("待推送id{}最终船舶高度为{}：".format(str(self.object_list.index(i) + 1), id_shiphm))
                            log.logger.info(
                                "目标{}船舶离相机距离为{}：".format(str(self.object_list.index(i) + 1), ship_camera_Distance))

                        # 推送一条数据后，删除self.box_count中的这个key
                        push_data = {
                            "id": str(self.object_list.index(i) + 1),
                            "snapTime": update_time,
                            "snapPos": self.init['snap_pos'],
                            "snapSubPos": self.init['snap_subpos'],
                            "snapDistance": ship_camera_Distance,
                            "snapDistanceAis": ship_camera_Distance_Ais,
                            "rcgShipSpd": id_speed,
                            "rcgShipLen": id_shiplen,
                            "rcgLongitude": id_gps_lgt,
                            "rcgLatitude": id_gps_lat,
                            "rcgHdg": 115,
                            "aisMmsi": aisMmsi,
                            "aisShipName": aisShipName,
                            "aisShipLen": "0",
                            "aisShipWidth": "0",
                            "aisShipSpd": aisShipSpd,
                            "aisShipType": "",
                            "aisHdg": heading,
                            "rcgPixSpeed": rcgPixSpeed,  # 像素速度
                            "rcgDirection": rcgDirection,  # 识别的航向，rcgDirection>0 船舶从左往右
                            "detBox": [int(i) for i in id_box_push],
                            "currentState": 0,  # 当前状态，0:未抓拍  1：已抓拍
                            "nAis": get_nais_data(self.ais_point_dict_copy),
                            "above_water_hm": self.ship_arguments_calculate.cam_hm,
                            "rcgLoadSts": "0",
                            "isOverTaking": -1,  # 是否追越
                            "islyingDown": -1 if float(aisShipSpd) > self.init['ship_lyingdown_speedThres'] or float(
                                aisShipSpd) < 0 else 1,  # 是否躺航（ais速度大于阈值，或者小于0，正常，否则为躺航）
                            "isReverse": is_reverse,  # 是否逆向
                            "detect_mode": int(self.init["shiptrack_camera_type"])  # 0星光枪 1热成像
                        }

                        put_box_section2_end = time.time()
                        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                            log.logger.info("第{}帧put_box_section2耗时{:.6}，秒".format(self.count,
                                                                                   put_box_section2_end - put_box_section1_end))

                        # log.logger.info("目标{}推送数据为{}：".format(str(self.object_list.index(i) + 1),push_data))
                        # if str(self.object_list.index(i) + 1) not in self.object_dict_push.keys():
                        #     log.logger.info("目标{}推送数据为:{}".format(str(self.object_list.index(i) + 1),json.dumps(push_data, ensure_ascii=False)))

                        # self.object_dict_push[str(self.object_list.index(i) + 1)] = {
                        #     "count": self.count,
                        #     "updTime": str(datetime.datetime.now()).replace("-", "").replace(":", "").replace(" ", "")[
                        #                4:14],
                        #     "mmsi": 0,
                        #     "aisName": "",
                        #     "ship_speed": id_speed,
                        #     "ship_len": id_shiplen,
                        #     "ship_hm": id_shiphm,
                        #     "ship_camera_distance": ship_camera_Distance,
                        #     "ship_speed_x": id_speed_x,
                        #     "ship_speed_y": id_speed_y,
                        # }
                        # log.logger.debug("self.object_dict_push列表为{}".format(self.object_dict_push))
                        # r = getRedis()
                        # 以目标确认前的数据来判断
                        # if self.parkship_detect(id_box):
                        # 已确认目标后的数据判断
                        # if self.parkship_detect(str(self.object_list.index(i) + 1),self.box_count_confirm[str(i)]) and self.pushship_confirm(str(self.object_list.index(i) + 1),id_box):
                        # if self.parkship_detect(str(self.object_list.index(i) + 1),self.box_count_confirm[str(i)]) and self.pushship_confirm(str(self.object_list.index(i) + 1),self.box_count_confirm[str(i)]):
                        # if self.parkship_detect(str(self.object_list.index(i) + 1),self.box_count_confirm[str(i)]) and self.pushship_confirm(str(self.object_list.index(i) + 1),self.box_count_confirm[str(i)]) and self.parallelship_detect(str(self.object_list.index(i) + 1),self.box_count_confirm[str(i)]):
                        if self.parkship_detect(str(self.object_list.index(i) + 1),
                                                self.box_count_confirm[str(i)]) and self.pushship_confirm(
                            str(self.object_list.index(i) + 1), self.box_count_confirm[str(i)]):
                            # 推送的数据才能附有id
                            self.object_dict_push[str(self.object_list.index(i) + 1)] = {
                                "count": self.count,
                                "updTime": str(datetime.datetime.now()).replace("-", "").replace(":", "").replace(" ",
                                                                                                                  "")[
                                           4:14],
                                "mmsi": 0,
                                "aisName": "",
                                "ship_speed": id_speed,
                                "ship_len": id_shiplen,
                                "ship_hm": id_shiphm,
                                "ship_camera_distance": ship_camera_Distance,
                                "ship_speed_x": id_speed_x,
                                "ship_speed_y": id_speed_y,
                            }
                            push_dataB = push_data.copy()
                            push_dataA = push_data.copy()
                            if int(self.init['redis_out_snap_mode']) == 0:
                                # redis_out_snap_mode=0 ,全貌细节都推送，且分开推送。
                                resultB = self.r.hget(self.snap_task_key_name,
                                                      str(self.object_list.index(i) + 1) + '.' + str(
                                                          self.object_list.index(i) + 1))
                                if resultB:
                                    if json.loads(resultB)["currentState"] != 0:
                                        push_dataB["currentState"] = json.loads(resultB)["currentState"]
                                    if int(json.loads(resultB)["rcgShipLen"]) != 0:
                                        push_dataB["rcgShipLen"] = json.loads(resultB)["rcgShipLen"]
                                    if int(json.loads(resultB)["snapDistanceAis"]) != 0:
                                        push_dataB["snapDistanceAis"] = json.loads(resultB)["snapDistanceAis"]
                                # 判断像素速度是否从配置文件中获取
                                if self.init["rcgPixSpeedMode"] == 1:
                                    if push_data["rcgDirection"] > 0:
                                        # 细节枪画面从左往右像素速度
                                        push_dataB["rcgPixSpeed"] = self.init["rcgPixSpeed"][0]
                                    else:
                                        # 细节枪画面从右往左船舶像素速度
                                        push_dataB["rcgPixSpeed"] = self.init["rcgPixSpeed"][1]
                                ##snapMode==2，推送细节数据
                                push_dataB["snapMode"] = 2
                                # 根据航向判断，和检测类型判断rcgSpeedpix
                                self.r.hset(self.snap_task_key_name,
                                            str(self.object_list.index(i) + 1) + '.' + str(
                                                self.object_list.index(i) + 1),
                                            json.dumps(push_dataB, ensure_ascii=False))
                                if self.count % (self.init['frame_rate'] * 10) == 0:
                                    log.logger.info("推送数据为{}".format(json.dumps(push_dataB, ensure_ascii=False)))

                                # log.logger.info("推送数据为{}".format(json.dumps(push_dataB)))

                                if int(self.init['redis_out_night_snap_detail_only']) == 1:
                                    if int(push_data['snapTime'].split(' ')[1].split(':')[0]) >= int(
                                            self.init['redis_out_day_end_time']) or int(
                                        push_data['snapTime'].split(' ')[1].split(':')[0]) <= int(
                                        self.init['redis_out_day_start_time']):
                                        pass
                                    else:
                                        # 推送全貌数据
                                        resultA = self.r.hget(self.snap_task_key_name,
                                                              str(self.object_list.index(i) + 1))
                                        if resultA:
                                            if json.loads(resultA)["currentState"] != 0:
                                                push_dataA["currentState"] = json.loads(resultA)["currentState"]
                                            if int(json.loads(resultA)["rcgShipLen"]) != 0:
                                                push_dataA["rcgShipLen"] = json.loads(resultA)["rcgShipLen"]
                                            if int(json.loads(resultA)["snapDistanceAis"]) != 0:
                                                push_dataA["snapDistanceAis"] = json.loads(resultA)["snapDistanceAis"]
                                        # 判断像素速度是否从配置文件中获取
                                        if self.init["rcgPixSpeedMode"] == 1:
                                            if push_dataA["rcgDirection"] > 0:
                                                # 全貌枪画面从左往右像素速度
                                                push_dataA["rcgPixSpeed"] = self.init["rcgPixSpeed"][2]
                                            else:
                                                # 全貌枪画面从右往左船舶像素速度
                                                push_dataA["rcgPixSpeed"] = self.init["rcgPixSpeed"][3]

                                        push_dataA["snapMode"] = 1
                                        self.r.hset(self.snap_task_key_name, str(self.object_list.index(i) + 1),
                                                    json.dumps(push_dataA, ensure_ascii=False))
                                        if self.count % (self.init['frame_rate'] * 10) == 0:
                                            log.logger.info(
                                                "推送数据为{}".format(json.dumps(push_dataA, ensure_ascii=False)))
                                else:
                                    # 推送全貌数据
                                    resultA = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i) + 1))

                                    if resultA:
                                        if json.loads(resultA)["currentState"] != 0:
                                            push_dataA["currentState"] = json.loads(resultA)["currentState"]
                                        if int(json.loads(resultA)["rcgShipLen"]) != 0:
                                            push_dataA["rcgShipLen"] = json.loads(resultA)["rcgShipLen"]
                                        if int(json.loads(resultA)["snapDistanceAis"]) != 0:
                                            push_dataA["snapDistanceAis"] = json.loads(resultA)["snapDistanceAis"]
                                    # 判断像素速度是否从配置文件中获取
                                    if self.init["rcgPixSpeedMode"] == 1:
                                        if push_dataA["rcgDirection"] > 0:
                                            # 全貌枪画面从左往右像素速度
                                            push_dataA["rcgPixSpeed"] = self.init["rcgPixSpeed"][2]
                                        else:
                                            # 全貌枪画面从右往左船舶像素速度
                                            push_dataA["rcgPixSpeed"] = self.init["rcgPixSpeed"][3]
                                    # log.logger.info("resultA为{}".format(json.dumps(resultA)))
                                    push_dataA["snapMode"] = 1
                                    self.r.hset(self.snap_task_key_name, str(self.object_list.index(i) + 1),
                                                json.dumps(push_dataA, ensure_ascii=False))
                                    if self.count % (self.init['frame_rate'] * 10) == 0:
                                        log.logger.info("推送数据为{}".format(json.dumps(push_dataA, ensure_ascii=False)))

                                # if int(self.init['redis_out_night_snap_detail_only']) == 1:
                                #     if int(push_data['snapTime'].split(' ')[1].split(':')[0]) >= int(
                                #             self.init['redis_out_day_end_time']) or int(
                                #             push_data['snapTime'].split(' ')[1].split(':')[0]) <= int(
                                #             self.init['redis_out_day_start_time']):
                                #         pass
                                #     else:
                                #         # 推送全貌数据
                                #         resultA = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i) + 1))
                                #         if resultA:
                                #             if json.loads(resultA)["currentState"] != 0:
                                #                 push_dataA["currentState"] = json.loads(resultA)["currentState"]
                                #         push_dataA["snapMode"] = 1
                                #         self.r.hset(self.snap_task_key_name, str(self.object_list.index(i) + 1),
                                #                json.dumps(push_dataA, ensure_ascii=False))
                                #         log.logger.info("推送数据为{}".format(json.dumps(push_dataA)))
                                # else:
                                #     # 推送全貌数据
                                #     resultA = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i) + 1))
                                #     if resultA:
                                #         if json.loads(resultA)["currentState"] != 0:
                                #             push_dataA["currentState"] = json.loads(resultA)["currentState"]
                                #     push_dataA["snapMode"] = 1
                                #     self.r.hset(self.snap_task_key_name, str(self.object_list.index(i) + 1),
                                #            json.dumps(push_dataA, ensure_ascii=False))
                                #     log.logger.info("推送数据为{}".format(json.dumps(push_dataA)))

                            elif int(self.init['redis_out_snap_mode']) == 1:
                                # 推送全貌数据
                                resultA = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i) + 1))
                                if resultA:
                                    if json.loads(resultA)["currentState"] != 0:
                                        push_data["currentState"] = json.loads(resultA)["currentState"]
                                    if int(json.loads(resultA)["rcgShipLen"]) != 0:
                                        push_data["rcgShipLen"] = json.loads(resultA)["rcgShipLen"]
                                    if int(json.loads(resultA)["snapDistanceAis"]) != 0:
                                        push_data["snapDistanceAis"] = json.loads(resultA)["snapDistanceAis"]
                                # 判断像素速度是否从配置文件中获取
                                if self.init["rcgPixSpeedMode"] == 1:
                                    if push_data["rcgDirection"] > 0:
                                        # 全貌枪画面从左往右像素速度
                                        push_data["rcgPixSpeed"] = self.init["rcgPixSpeed"][2]
                                    else:
                                        # 全貌枪画面从右往左船舶像素速度
                                        push_data["rcgPixSpeed"] = self.init["rcgPixSpeed"][3]
                                push_data["snapMode"] = 1
                                self.r.hset(self.snap_task_key_name, str(self.object_list.index(i) + 1),
                                            json.dumps(push_data, ensure_ascii=False))
                                if self.count % (self.init['frame_rate'] * 10) == 0:
                                    log.logger.info("推送数据为{}".format(json.dumps(push_data, ensure_ascii=False)))

                            elif int(self.init['redis_out_snap_mode']) == 2:

                                if int(self.init['res_task_key_name_copy_activate']) == 1:
                                    push_data_copy = push_data.copy()
                                    # 推送细节数据(往key1推送)
                                    resultB = self.r.hget(self.snap_task_key_name,
                                                          str(self.object_list.index(i) + 1) + '.' + str(
                                                              self.object_list.index(i) + 1))
                                    if resultB:
                                        if json.loads(resultB)["currentState"] != 0:
                                            push_data["currentState"] = json.loads(resultB)["currentState"]
                                        if int(json.loads(resultB)["rcgShipLen"]) != 0:
                                            push_data["rcgShipLen"] = json.loads(resultB)["rcgShipLen"]
                                        if int(json.loads(resultB)["snapDistanceAis"]) != 0:
                                            push_data["snapDistanceAis"] = json.loads(resultB)["snapDistanceAis"]

                                    # 判断像素速度是否从配置文件中获取
                                    if self.init["rcgPixSpeedMode"] == 1:
                                        if push_data["rcgDirection"] > 0:
                                            # 细节枪画面从左往右像素速度
                                            push_data["rcgPixSpeed"] = self.init["rcgPixSpeed"][0]
                                        else:
                                            # 细节枪画面从右往左船舶像素速度
                                            push_data["rcgPixSpeed"] = self.init["rcgPixSpeed"][1]
                                    push_data["snapMode"] = 2

                                    self.r.hset(self.snap_task_key_name,
                                                str(self.object_list.index(i) + 1) + '.' + str(
                                                    self.object_list.index(i) + 1),
                                                json.dumps(push_data, ensure_ascii=False))
                                    if self.count % (self.init['frame_rate'] * 10) == 0:
                                        log.logger.info("推送数据为{}".format(json.dumps(push_data, ensure_ascii=False)))

                                    resultB_key2 = self.r.hget(self.snap_task_key_name + '_copy',
                                                               str(self.object_list.index(i) + 1) + '.' + str(
                                                                   self.object_list.index(i) + 1))
                                    if resultB_key2:
                                        push_data_copy["snapPos"] = push_data_copy["snapPos"] + '_copy'
                                        if json.loads(resultB_key2)["currentState"] != 0:
                                            push_data_copy["currentState"] = json.loads(resultB_key2)["currentState"]
                                        if int(json.loads(resultB_key2)["rcgShipLen"]) != 0:
                                            push_data_copy["rcgShipLen"] = json.loads(resultB_key2)["rcgShipLen"]
                                        if int(json.loads(resultB_key2)["snapDistanceAis"]) != 0:
                                            push_data_copy["snapDistanceAis"] = json.loads(resultB_key2)[
                                                "snapDistanceAis"]
                                    # 判断像素速度是否从配置文件中获取
                                    if self.init["rcgPixSpeedMode"] == 1:
                                        if push_data_copy["rcgDirection"] > 0:
                                            # 细节枪画面从左往右像素速度
                                            push_data_copy["rcgPixSpeed"] = self.init["rcgPixSpeed"][0]
                                        else:
                                            # 细节枪画面从右往左船舶像素速度
                                            push_data_copy["rcgPixSpeed"] = self.init["rcgPixSpeed"][1]
                                    push_data_copy["snapMode"] = 2
                                    self.r.hset(self.snap_task_key_name + '_copy',
                                                str(self.object_list.index(i) + 1) + '.' + str(
                                                    self.object_list.index(i) + 1),
                                                json.dumps(push_data_copy, ensure_ascii=False))
                                    if self.count % (self.init['frame_rate'] * 10) == 0:
                                        log.logger.info(
                                            "推送copy数据为{}".format(json.dumps(push_data_copy, ensure_ascii=False)))

                                else:
                                    # 推送细节数据
                                    resultB = self.r.hget(self.snap_task_key_name,
                                                          str(self.object_list.index(i) + 1) + '.' + str(
                                                              self.object_list.index(i) + 1))
                                    if resultB:
                                        if json.loads(resultB)["currentState"] != 0:
                                            push_data["currentState"] = json.loads(resultB)["currentState"]
                                        if int(json.loads(resultB)["rcgShipLen"]) != 0:
                                            push_data["rcgShipLen"] = json.loads(resultB)["rcgShipLen"]
                                        if int(json.loads(resultB)["snapDistanceAis"]) != 0:
                                            push_data["snapDistanceAis"] = json.loads(resultB)["snapDistanceAis"]
                                    # 判断像素速度是否从配置文件中获取
                                    if self.init["rcgPixSpeedMode"] == 1:
                                        if push_data["rcgDirection"] > 0:
                                            # 细节枪画面从左往右像素速度
                                            push_data["rcgPixSpeed"] = self.init["rcgPixSpeed"][0]
                                        else:
                                            # 细节枪画面从右往左船舶像素速度
                                            push_data["rcgPixSpeed"] = self.init["rcgPixSpeed"][1]
                                    push_data["snapMode"] = 2
                                    self.r.hset(self.snap_task_key_name,
                                                str(self.object_list.index(i) + 1) + '.' + str(
                                                    self.object_list.index(i) + 1),
                                                json.dumps(push_data, ensure_ascii=False))
                                    if self.count % (self.init['frame_rate'] * 10) == 0:
                                        log.logger.info(
                                            "推送数据为{}".format(json.dumps(push_data, ensure_ascii=False)))

                            else:
                                # 推送全貌数据
                                resultC = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i) + 1))
                                if resultC:
                                    if json.loads(resultC)["currentState"] != 0:
                                        push_data["currentState"] = json.loads(resultC)["currentState"]
                                    if int(json.loads(resultC)["rcgShipLen"]) != 0:
                                        push_data["rcgShipLen"] = json.loads(resultC)["rcgShipLen"]
                                    if int(json.loads(resultC)["snapDistanceAis"]) != 0:
                                        push_data["snapDistanceAis"] = json.loads(resultC)["snapDistanceAis"]
                                push_data["snapMode"] = 0
                                self.r.hset(self.snap_task_key_name, str(self.object_list.index(i) + 1),
                                            json.dumps(push_data, ensure_ascii=False))
                                if self.count % (self.init['frame_rate'] * 10) == 0:
                                    log.logger.info("推送数据为{}".format(json.dumps(push_data, ensure_ascii=False)))
                            saveframe = cv2ImgAddText(self.frame, "cap", int(push_data["detBox"][0]) - 30,
                                                      int(push_data["detBox"][1]) - 20, (0, 255, 0), 20)

                            # self.frame = cv2ImgAddText(self.frame, "id = {}".format(push_data["id"], push_data["detBox"][0], push_data["detBox"][1] - 14,(0, 255, 0), 14)
                            cv2.rectangle(saveframe, (int(push_data["detBox"][0]), int(push_data["detBox"][1])),
                                          (int(push_data["detBox"][2]), int(push_data["detBox"][3])), (0, 255, 0),
                                          thickness=1)
                            # 背景所处位置 图像中间顶部
                            if aisShipName:
                                text_bg_x1 = 20
                                text_bg_y1 = 670
                                text_bg_x2 = text_bg_x1 + 700
                                text_bg_y2 = 710
                            else:
                                text_bg_x1 = 20
                                text_bg_y1 = 670
                                text_bg_x2 = text_bg_x1 + 500
                                text_bg_y2 = 710

                            fill_color = (255, 230, 0)

                            blk = np.zeros(saveframe.shape, np.uint8)

                            cv2.rectangle(blk, (text_bg_x1, text_bg_y1), (text_bg_x2, text_bg_y2), fill_color,
                                          -1)  # 注意在 blk的基础上进行绘制；
                            saveframe = cv2.addWeighted(saveframe, 1.0, blk, 0.67, 1)

                            # # 背景框上 写字
                            # raw_src = put_chinese_string(raw_src, text_bg_x1 + 12, text_bg_y1 + 12,
                            #                              "吃水线刻度：{}m".format(0.0))

                            saveframe = cv2ImgAddText(saveframe,
                                                      "{} {} 距离：{}米 aisname:{} mmsi:{}".format(push_data["snapPos"],
                                                                                               "上行" if int(push_data[
                                                                                                               "rcgDirection"]) *
                                                                                                       self.init[
                                                                                                           "factorSet"] > 0 else "下行",
                                                                                               int(push_data[
                                                                                                       "snapDistance"]),
                                                                                               aisShipName, aisMmsi),
                                                      20,
                                                      680, (0, 0, 0), 20)

                            dirpath = os.path.join(self.init['save_path'], str(self.object_list.index(i) + 1))
                            # if self.init['ship_overtaking_activate'] == 1:
                            #     self.temppusher[str(self.object_list.index(i) + 1)] = VideoPusher(self.init)
                            #     self.pusher.push_video(saveframe,str(self.object_list.index(i) + 1),dirpath)

                            try:
                                if not os.path.exists(dirpath):
                                    os.makedirs(dirpath)
                                try:
                                    if self.init['ship_overtaking_activate'] == 1:
                                        self.temppusher[str(self.object_list.index(i) + 1)].push_video(saveframe,
                                                                                                       dirpath)
                                except:
                                    log.logger.error(traceback.format_exc())
                                    # print("self.temppusherlen",len(self.temppusher))

                                # 如果数据不更新，释放资源
                                # print("self.object_dict_push[str(self.object_list.index(i) + 1)]",str(self.object_list.index(i) + 1),self.object_dict_push[str(self.object_list.index(i) + 1)]["updTime"])

                                # if os.path.exists(os.path.join(dirpath, '200_检测相机截图.jpg')):
                                #     continue
                                # else:
                                #     if  int((int(push_data["detBox"][0]) + int(push_data["detBox"][2]))/2) > int(self.frame.shape[1])/2 - 50 and int((int(push_data["detBox"][0]) + int(push_data["detBox"][2]))/2) < int(self.frame.shape[1])/2 + 50:
                                #     #if int(push_data["detBox"][0]) >10:
                                #         # 加上cap的标识
                                #         cv2.imencode('.jpg', saveframe)[1].tofile(os.path.join(dirpath, '200_检测相机截图.jpg'))

                                # cv2.imencode('.jpg', saveframe)[1].tofile(os.path.join(dirpath, '200_检测相机截图.jpg'))

                                if int((int(push_data["detBox"][0]) + int(push_data["detBox"][2])) / 2) > int(
                                        self.frame.shape[1]) / 2 - 50 and int(
                                    (int(push_data["detBox"][0]) + int(push_data["detBox"][2])) / 2) < int(
                                    self.frame.shape[1]) / 2 + 50:
                                    cv2.imencode('.jpg', saveframe)[1].tofile(os.path.join(dirpath, '200_检测相机截图.jpg'))
                                else:
                                    if os.path.exists(os.path.join(dirpath, '200_检测相机截图.jpg')):
                                        continue
                                    else:
                                        cv2.imencode('.jpg', saveframe)[1].tofile(
                                            os.path.join(dirpath, '200_检测相机截图.jpg'))

                                    # if os.path.exists(os.path.join(dirpath, '200_检测相机截图.jpg')):
                                    #     continue
                                    # else:
                                    #     cv2.imencode('.jpg', saveframe)[1].tofile(
                                    #         os.path.join(dirpath, '200_检测相机截图.jpg'))
                                # if os.path.exists(os.path.join(dirpath, '200_检测相机截图.jpg')):
                                #     continue
                                # else:
                                #     if  int((int(push_data["detBox"][0]) + int(push_data["detBox"][2]))/2) > int(self.frame.shape[1])/2 - 50 and int((int(push_data["detBox"][0]) + int(push_data["detBox"][2]))/2) < int(self.frame.shape[1])/2 + 50:
                                #     #if int(push_data["detBox"][0]) >10:
                                #         # 加上cap的标识
                                #         cv2.imencode('.jpg', saveframe)[1].tofile(os.path.join(dirpath, '200_检测相机截图.jpg'))
                            except:
                                log.logger.error(traceback.format_exc())
                        else:
                            if str(self.object_list.index(i) + 1) not in self.no_push_id:
                                log.logger.info("目标{}为停泊船，数据不推送".format(str(self.object_list.index(i) + 1)))
                            self.no_push_id.append(str(self.object_list.index(i) + 1))
                        put_box_section3_end = time.time()
                        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                            log.logger.info("第{}帧put_box_section3耗时{:.6}，秒".format(self.count,
                                                                                   put_box_section3_end - put_box_section2_end))
                            # 江停泊船的id和box存放到字典里
                            # self.no_push_id_dict[str(self.object_list.index(i) + 1)] = push_data["detBox"]
                        ####船载要求，只推送一条数据
                        # break
                    except:
                        log.logger.error(traceback.format_exc())

    def update_box_count(self):
        ##待删除的目标id
        del_list = []
        for i in self.box_count.keys():
            t = max(self.box_count[i].keys(), key=int)
            if int(t) + 1200 * 24 < int(self.count):
                log.logger.debug("目标id{}在2分钟内未出现，删除该id信息".format(i))
                del_list.append(i)
        for i in del_list:
            del self.box_count[i]

    # 更新停泊船字典
    def update_no_push_id_dict(self):
        result = {}
        for box_id1, box_coords1 in self.no_push_id_dict.items():
            keep_box = True

            for box_id2, box_coords2 in self.no_push_id_dict.items():
                if box_id1 != box_id2:
                    iou = self.calculate_iou(box_coords1, box_coords2)
                    if iou > 0.9:
                        if int(box_id1) < int(box_id2):
                            keep_box = False
                            break
            if keep_box:
                result[box_id1] = box_coords1

        sorted_data = sorted(result.items(), key=lambda x: int(x[0]), reverse=True)
        result = dict(sorted_data[:3])

        # 更新停泊船字典
        self.no_push_id_dict = result

    # 更新推送视频流字典，不更新的目标及时清理掉,在删除之前判断是否有追越行为
    def update_pushvideo(self):
        if self.temppusher:
            del_key = []
            for key, value in self.temppusher.items():
                try:
                    result = self.r.hget(self.snap_task_key_name, str(key))
                    if not result:
                        result = self.r.hget(self.snap_task_key_name, str(key) + '.' + str(key))

                    redis_json = json.loads(result)

                    time_diff = (datetime.datetime.now() - datetime.datetime.strptime(redis_json['snapTime'],
                                                                                      '%Y/%m/%d %H:%M:%S')).total_seconds()
                    # 如果redis数据时间与当前时间差值大于指定时间，则认为数据过期
                    if time_diff > 5:
                        log.logger.info('id{}上次更新数据时间：{}，数据过期，删除视频流句柄'.format(key, redis_json['snapTime']))
                        log.logger.info("id:{},确认的box列表为{}".format(key, self.box_count_confirm[
                            str(self.object_list[int(key) - 1])]))

                        is_overtaking = self.judge_overtaking(key, self.box_count_confirm[
                            str(self.object_list[int(key) - 1])])
                        if is_overtaking:
                            log.logger.info("id:{},存在追越行为".format(key))
                            redis_json["isOverTaking"] = 1
                        else:
                            log.logger.info("id:{},不存在追越行为".format(key))
                            redis_json["isOverTaking"] = 0
                        log.logger.info("目标{}推送追越数据为{}".format(key, json.dumps(redis_json, ensure_ascii=False)))

                        # 全貌细节都推送，且分开推送
                        if int(self.init['redis_out_snap_mode']) == 0:
                            # 先推送细节
                            self.r.hset(self.snap_task_key_name, str(key) + '.' + str(key),
                                        json.dumps(redis_json, ensure_ascii=False))
                            if int(self.init['redis_out_night_snap_detail_only']) == 1:
                                # 开启夜间不推送全貌功能
                                if int(redis_json['snapTime'].split(' ')[1].split(':')[0]) >= int(
                                        self.init['redis_out_day_end_time']) or int(
                                    redis_json['snapTime'].split(' ')[1].split(':')[0]) <= int(
                                    self.init['redis_out_day_start_time']):
                                    pass
                                else:
                                    self.r.hset(self.snap_task_key_name, str(key),
                                                json.dumps(redis_json, ensure_ascii=False))
                            else:
                                # 推送全貌数据
                                self.r.hset(self.snap_task_key_name, str(key),
                                            json.dumps(redis_json, ensure_ascii=False))
                        # 推送全貌数据
                        elif int(self.init['redis_out_snap_mode']) == 1:
                            self.r.hset(self.snap_task_key_name, str(key), json.dumps(redis_json, ensure_ascii=False))
                        elif int(self.init['redis_out_snap_mode']) == 2:
                            # 推送细节数据
                            self.r.hset(self.snap_task_key_name, str(key) + '.' + str(key),
                                        json.dumps(redis_json, ensure_ascii=False))
                        else:
                            # 全貌、细节数据都推送（一起推送）
                            self.r.hset(self.snap_task_key_name, str(key), json.dumps(redis_json, ensure_ascii=False))

                        # 删除self.box_count_confirm
                        del self.box_count_confirm[str(self.object_list[int(key) - 1])]
                        del_key.append(key)
                except:
                    log.logger.error(traceback.format_exc())
            for i in del_key:
                log.logger.info("id:{},删除该视频流句柄".format(i))
                del self.temppusher[i]

        # 从推送数据实时获取数据
        # result = self.r.hget(self.snap_task_key_name, str(id))
        # if not result:
        # for key,value in self.temppusher.items():
        #     print(key)

    def updata_box_count_confirm(self):
        # 20231007，暂时不更新updata_box_count_confirm，需要全流程记录box，用于判断追越，追越行为跟停泊船判断有冲突，两者不可兼容。加个开关
        if int(self.init['ship_overtaking_activate']) == 0:
            pre_del_dict = {}
            for i in self.box_count_confirm.keys():
                # 按照key从小到大排序
                sorted_keys = sorted(self.box_count_confirm[i].keys(), key=lambda i: int(i))
                if len(sorted_keys) < 20:
                    pass
                else:
                    pre_del_dict[i] = sorted_keys[:-20]
                    pre_del_dict[i] = sorted_keys[:-50]
            for key, value in pre_del_dict.items():
                for delkey in value:
                    del self.box_count_confirm[key][str(delkey)]

    def update_ais_imerge_info(self):
        ##待删除的目标id
        del_list = []
        for i in self.ais_imerge_info.keys():
            t = max(self.ais_imerge_info[i].keys(), key=int)
            if int(t) + 1200 * 24 < int(self.count):
                log.logger.debug("目标id{}在2分钟内未出现，删除该id信息".format(i))
                del_list.append(i)
        for i in del_list:
            del self.ais_imerge_info[i]

    def ais_imergebak(self):
        try:
            ais_imerge_section1_start = time.time()
            object_dict = {}
            ##算法逻辑 ais目标与确认的船舶目标进行融合。
            ##以self.object_dict_push为索引媒介，找到当前确认的目标self.trackers_C中的id对应的box（self.object_dict_push和self.trackers_C中的子集），然后跟ais进行融合
            if len(self.trackers_C) and self.ais_point_dict_copy:
                ##获取确定目标的id
                last_col_list_C = [int(t) for t in self.trackers_C[:, -1].tolist()]
                ##获取同时在list_left_to_right中和trackers_C中的id列表，并且i不在不推送列表里并且在该列表用于ais融合,以及str(self.object_list.index(int(i)) + 1) 在推送字典列表里（防止停泊船等不推送船舶）
                # ais_match_list = [i for i in self.object_list if i in self.trackers_C if i not in self.no_push_id]
                # ais_match_list = [i for i in self.object_list if i in last_col_list_C if i not in self.no_push_id]
                ais_match_list = [i for i in self.object_list if i in last_col_list_C if i not in self.no_push_id if
                                  str(self.object_list.index(int(i)) + 1) in self.object_dict_push.keys()]
                # 如果待匹配不为空
                if ais_match_list:
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.debug("self.trackers_C为{}".format(self.trackers_C))
                        log.logger.debug("ais_match_list为{}".format(ais_match_list))
                        log.logger.debug("last_col_list_C为{}".format(last_col_list_C))

                    for i in ais_match_list:
                        if self.init['ais_objection_activate'] == 1:
                            result = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i)))
                            if not result:
                                result = self.r.hget(self.snap_task_key_name,
                                                     str(self.object_list.index(i)) + '.' + str(
                                                         self.object_list.index(i)))
                            redis_json = json.loads(result)
                            if int(redis_json["rcgDirection"]) == self.init['ais_objection_math_direction']:
                                object_dict[str(self.object_list.index(i))] = {
                                    'updTime': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                        'updTime'],
                                    'ship_len': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                        'ship_len'],
                                    'ship_speed': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                        'ship_speed'],
                                    'box': [float(t) for t in
                                            self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][0:-1],
                                    'lgt': self.ship_arguments_calculate.Com_Pt2GpsGet(
                                        [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                        0:-1])[0],
                                    'lat': self.ship_arguments_calculate.Com_Pt2GpsGet(
                                        [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                        0:-1])[1]
                                }
                            else:
                                log.logger.info("船舶航向为从右向左，不做ais融合{}".format(redis_json))
                        else:
                            object_dict[str(self.object_list.index(i))] = {
                                'updTime': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                    'updTime'],
                                'ship_len': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                    'ship_len'],
                                'ship_speed': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                    'ship_speed'],
                                'box': [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                       0:-1],
                                'lgt': self.ship_arguments_calculate.Com_Pt2GpsGet(
                                    [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                    0:-1])[0],
                                'lat': self.ship_arguments_calculate.Com_Pt2GpsGet(
                                    [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                    0:-1])[1]
                            }
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.info("待匹配ais信息为{}".format(self.ais_point_dict_copy))
                        log.logger.info("待匹配目标id信息为{}".format(object_dict))
                        log.logger.debug("self.ais_imerge_info为{}".format(self.ais_imerge_info))
                        log.logger.info("self.ais_pick为{}".format(self.ais_pick))
                        log.logger.info("self.pop_ais为{}".format(self.pop_ais))

                    # 待匹配的目标（算法检测确认的目标）key值提取，并按照以小到大排序
                    object_dict_keylist = list(object_dict.keys())
                    object_dict_keylist.sort()
                    # ais数据key值提取，并按照以小到大排序
                    # 内河版增加过滤，只采用actual的ais数据，不用predict的数据
                    # filtered_dict = {k: v for k, v in self.ais_point_dict_copy.items() if any(x['source'] == 'actual' for x in v.values())}

                    ais_point_dict_keylist = list(self.ais_point_dict_copy.keys())
                    ais_point_dict_keylist.sort()
                    ais_imerge_section1_end = time.time()
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.info(
                            "第{}帧ais融合section1耗时{:.6}，秒".format(self.count,
                                                                ais_imerge_section1_end - ais_imerge_section1_start))

                    def operation():
                        # 这个表达式暂定为两点的欧氏距离公式
                        # return lambda u, v: np.sqrt(np.sum((u - v) ** 2))
                        return lambda u, v: self.ship_arguments_calculate.calculate_lgtlat_distance(u[0], u[1], v[0],
                                                                                                    v[1])

                    # 带预测匹配的ais列表
                    ais_array = []
                    for _, v in sorted(self.ais_point_dict_copy.items()):
                        # ais_array.append(v[max(v.keys())]['point'])
                        ais_array.append((v[max(v.keys())]['lgt'], v[max(v.keys())]['lat']))
                    ais_array = np.array(ais_array)
                    # 带预测的id列表
                    id_push_list = []
                    for _, v in sorted(object_dict.items()):
                        id_push_list.append(
                            [
                                v['lgt'],
                                v['lat']
                            ]
                        )
                    id_push_list = np.array(id_push_list)
                    # 代价矩阵
                    cost = cdist(ais_array, id_push_list, metric=operation())
                    row_ind, col_ind = linear_sum_assignment(cost)
                    ais_imerge_section2_end = time.time()
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.info(
                            "第{}帧ais融合section2耗时{:.6}，秒".format(self.count,
                                                                ais_imerge_section2_end - ais_imerge_section1_end))

                    # log.logger.debug("self.ais_imerge_info为{}".format(self.ais_imerge_info))
                    for idx, i in enumerate(col_ind):
                        # cost[row_ind, col_ind])  # 提取每个行索引的最优指派列索引所在的元素，形成数组
                        # 将匹配信息存入到字典里
                        if str(object_dict_keylist[i]) in self.ais_imerge_info.keys():
                            self.ais_imerge_info[str(object_dict_keylist[i])][str(self.count)] = {
                                "mmsi": ais_point_dict_keylist[row_ind[idx]],
                                "dictance": cost[row_ind, col_ind][idx]
                            }
                        else:
                            self.ais_imerge_info[str(object_dict_keylist[i])] = {
                                str(self.count): {
                                    "mmsi": ais_point_dict_keylist[row_ind[idx]],
                                    "dictance": cost[row_ind, col_ind][idx]
                                }
                            }
                        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                            log.logger.debug("目标id：{}匹配对应的mmsi为{}，代价函数为{},距离为{}".format(object_dict_keylist[i],
                                                                                        ais_point_dict_keylist[
                                                                                            row_ind[idx]],
                                                                                        cost[row_ind, col_ind][idx],
                                                                                        cost[row_ind, col_ind][idx]))

            ais_imerge_section3_start = time.time()
            if len(self.ais_imerge_info):
                filtered_dict = {k: v for k, v in self.ais_imerge_info.items() if k in object_dict.keys()}
                for key, value in filtered_dict.items():
                    # if len(value) < 5:
                    if len(value) <= int(self.init['ais_match_times']):
                        continue
                    mmsi_list = []
                    distance_list = []
                    for i in value.keys():
                        if value[i]['mmsi'] in self.ais_pick.keys():
                            continue
                        mmsi_list.append(value[i]['mmsi'])
                        distance_list.append(value[i]['dictance'])
                    if len(mmsi_list) == 0:
                        continue
                    mmsi_mode = max(set(mmsi_list), key=mmsi_list.count)
                    if mmsi_mode not in self.pop_ais:
                        # 计算该众数mmsi对应的distance的平均值
                        distance_sum = 0
                        for i in range(len(mmsi_list)):
                            if mmsi_list[i] == mmsi_mode:
                                distance_sum += distance_list[i]
                        distance_mean = distance_sum / mmsi_list.count(mmsi_mode)
                        if int(distance_mean) < int(cfg["Ais"]["pair_dm_th"]):
                            log.logger.debug("mmsi：{}，目标id：{}之间的距离均值为{}".format(mmsi_mode, key, distance_mean))
                            # 更新self.ais_pick字典(key为mmsi，value为目标id,从1开始计数),并且字典key只更新一次
                            if str(int(key) + 1) not in self.ais_pick.values():
                                self.ais_pick[mmsi_mode] = str(int(key) + 1)
                                # 将ais添加到不需要匹配的ais列表里
                                self.pop_ais.append(mmsi_mode)
            ais_imerge_section3_end = time.time()
            if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                log.logger.info(
                    "第{}帧ais融合section3耗时{:.6}，秒".format(self.count,
                                                        ais_imerge_section3_end - ais_imerge_section3_start))
        except:
            log.logger.error(traceback.format_exc())

    def ais_imerge(self):
        try:
            ais_imerge_section1_start = time.time()
            object_dict = {}
            ##算法逻辑 ais目标与确认的船舶目标进行融合。
            ##以self.object_dict_push为索引媒介，找到当前确认的目标self.trackers_C中的id对应的box（self.object_dict_push和self.trackers_C中的子集），然后跟ais进行融合
            if len(self.trackers_C) and self.ais_point_dict_copy:
                ##获取确定目标的id
                last_col_list_C = [int(t) for t in self.trackers_C[:, -1].tolist()]
                ##获取同时在list_left_to_right中和trackers_C中的id列表，并且i不在不推送列表里并且在该列表用于ais融合,以及str(self.object_list.index(int(i)) + 1) 在推送字典列表里（防止停泊船等不推送船舶）
                ais_match_list = [i for i in self.object_list if i in last_col_list_C if i not in self.no_push_id if
                                  str(self.object_list.index(int(i)) + 1) in self.object_dict_push.keys()]
                # 如果待匹配不为空
                if ais_match_list:
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.debug("self.trackers_C为{}".format(self.trackers_C))
                        log.logger.debug("ais_match_list为{}".format(ais_match_list))
                        log.logger.debug("last_col_list_C为{}".format(last_col_list_C))

                    for i in ais_match_list:
                        # if self.init['ais_objection_activate'] == 1:
                        #    try:
                        #         result = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i)))
                        #         if not result:
                        #             result = self.r.hget(self.snap_task_key_name, str(self.object_list.index(i)) + '.' + str(self.object_list.index(i)))
                        #         redis_json = json.loads(result)
                        #         if int(redis_json["rcgDirection"]) == self.init['ais_objection_math_direction']:
                        #             object_dict[str(self.object_list.index(i))] = {
                        #                 'updTime': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                        #                     'updTime'],
                        #                 'ship_len': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                        #                     'ship_len'],
                        #                 'ship_speed': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                        #                     'ship_speed'],
                        #                 'box': [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][0:-1],
                        #                 'lgt': self.ship_arguments_calculate.Com_Pt2GpsGet(
                        #                     [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][0:-1])[0],
                        #                 'lat': self.ship_arguments_calculate.Com_Pt2GpsGet(
                        #                     [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][0:-1])[1]
                        #             }
                        #         else:
                        #             log.logger.info("船舶航向为从右向左，不做ais融合{}".format(redis_json))
                        #    except:
                        #        log.logger.debug(traceback.format_exc())
                        # else:
                        object_dict[str(self.object_list.index(i))] = {
                            'updTime': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                'updTime'],
                            'ship_len': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                'ship_len'],
                            'ship_speed': self.object_dict_push[str(self.object_list.index(int(i)) + 1)][
                                'ship_speed'],
                            'box': [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                   0:-1],
                            'lgt': self.ship_arguments_calculate.Com_Pt2GpsGet(
                                [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                0:-1])[0],
                            'lat': self.ship_arguments_calculate.Com_Pt2GpsGet(
                                [float(t) for t in self.trackers_C[last_col_list_C.index(int(i)), :].tolist()][
                                0:-1])[1]
                        }

                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.info("待匹配ais信息为{}".format(self.ais_point_dict_copy))
                        log.logger.info("待匹配目标id信息为{}".format(object_dict))
                        log.logger.info("self.ais_imerge_info为{}".format(self.ais_imerge_info))
                        log.logger.info("self.ais_pick为{}".format(self.ais_pick))
                        log.logger.info("self.pop_ais为{}".format(self.pop_ais))

                    # 待匹配的目标（算法检测确认的目标）key值提取，并按照以小到大排序
                    object_dict_keylist = list(object_dict.keys())
                    object_dict_keylist.sort()
                    # ais数据key值提取，并按照以小到大排序
                    # 内河版增加过滤，只采用actual的ais数据，不用predict的数据
                    # filtered_dict = {k: v for k, v in self.ais_point_dict_copy.items() if any(x['source'] == 'actual' for x in v.values())}

                    ais_point_dict_keylist = list(self.ais_point_dict_copy.keys())
                    ais_point_dict_keylist.sort()
                    ais_imerge_section1_end = time.time()
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.info(
                            "第{}帧ais融合section1耗时{:.6}，秒".format(self.count,
                                                                ais_imerge_section1_end - ais_imerge_section1_start))

                    def operation():
                        # 这个表达式暂定为两点的欧氏距离公式
                        # return lambda u, v: np.sqrt(np.sum((u - v) ** 2))
                        return lambda u, v: self.ship_arguments_calculate.calculate_lgtlat_distance(u[0], u[1], v[0],
                                                                                                    v[1])

                    # 带预测匹配的ais列表
                    ais_array = []
                    for _, v in sorted(self.ais_point_dict_copy.items()):
                        # ais_array.append(v[max(v.keys())]['point'])
                        ais_array.append((v[max(v.keys())]['lgt'], v[max(v.keys())]['lat']))
                    ais_array = np.array(ais_array)
                    # 带预测的id列表
                    id_push_list = []
                    for _, v in sorted(object_dict.items()):
                        id_push_list.append(
                            [
                                v['lgt'],
                                v['lat']
                            ]
                        )
                    id_push_list = np.array(id_push_list)
                    # 代价矩阵
                    cost = cdist(ais_array, id_push_list, metric=operation())
                    row_ind, col_ind = linear_sum_assignment(cost)
                    ais_imerge_section2_end = time.time()
                    if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                        log.logger.info(
                            "第{}帧ais融合section2耗时{:.6}，秒".format(self.count,
                                                                ais_imerge_section2_end - ais_imerge_section1_end))

                    # log.logger.debug("self.ais_imerge_info为{}".format(self.ais_imerge_info))
                    for idx, i in enumerate(col_ind):
                        # cost[row_ind, col_ind])  # 提取每个行索引的最优指派列索引所在的元素，形成数组
                        # 将匹配信息存入到字典里
                        if str(object_dict_keylist[i]) in self.ais_imerge_info.keys():
                            self.ais_imerge_info[str(object_dict_keylist[i])][str(self.count)] = {
                                "mmsi": ais_point_dict_keylist[row_ind[idx]],
                                "dictance": cost[row_ind, col_ind][idx]
                            }
                        else:
                            self.ais_imerge_info[str(object_dict_keylist[i])] = {
                                str(self.count): {
                                    "mmsi": ais_point_dict_keylist[row_ind[idx]],
                                    "dictance": cost[row_ind, col_ind][idx]
                                }
                            }
                        if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                            log.logger.debug("目标id：{}匹配对应的mmsi为{}，代价函数为{},距离为{}".format(object_dict_keylist[i],
                                                                                        ais_point_dict_keylist[
                                                                                            row_ind[idx]],
                                                                                        cost[row_ind, col_ind][idx],
                                                                                        cost[row_ind, col_ind][idx]))

            ais_imerge_section3_start = time.time()
            if len(self.ais_imerge_info):
                filtered_dict = {k: v for k, v in self.ais_imerge_info.items() if k in object_dict.keys()}
                for key, value in filtered_dict.items():
                    if len(value) <= int(self.init['ais_match_times']):
                        continue
                    mmsi_list = []
                    distance_list = []
                    for i in value.keys():
                        if value[i]['mmsi'] in self.ais_pick.keys():
                            continue
                        mmsi_list.append(value[i]['mmsi'])
                        distance_list.append(value[i]['dictance'])
                    if len(mmsi_list) == 0:
                        continue
                    mmsi_mode = max(set(mmsi_list), key=mmsi_list.count)
                    if mmsi_mode not in self.pop_ais:
                        # 计算该众数mmsi对应的distance的平均值
                        distance_sum = 0
                        for i in range(len(mmsi_list)):
                            if mmsi_list[i] == mmsi_mode:
                                distance_sum += distance_list[i]
                        distance_mean = distance_sum / mmsi_list.count(mmsi_mode)
                        # 20231008 新增逻辑，如果目标和附近的ais信号都为1，则直接匹配
                        if len(self.trackers_C) and len([int(t) for t in self.trackers_C[:, -1].tolist()]) == 1 and len(
                                self.ais_point_dict_copy) == 1:
                            log.logger.debug(
                                "mmsi：{}，目标id：{}之间的距离均值为{},由于当前mmsi和目标id都是1，直接匹配".format(mmsi_mode, key, distance_mean))
                            # 更新self.ais_pick字典(key为mmsi，value为目标id,从1开始计数),并且字典key只更新一次
                            if str(int(key) + 1) not in self.ais_pick.values():
                                self.ais_pick[mmsi_mode] = str(int(key) + 1)
                                # 将ais添加到不需要匹配的ais列表里
                                self.pop_ais.append(mmsi_mode)
                        else:
                            # ais数据key值提取，并按照以小到大排序
                            # 内河版增加过滤，只采用actual的ais数据，不用predict的数据
                            # filtered_dict = {k: v for k, v in self.ais_point_dict_copy.items() if any(x['source'] == 'actual' for x in v.values())}
                            # ais_point_dict_keylist = list(self.ais_point_dict_copy.keys())
                            if int(distance_mean) < int(cfg["Ais"]["pair_dm_th"]):
                                log.logger.debug("mmsi：{}，目标id：{}之间的距离均值为{}".format(mmsi_mode, key, distance_mean))
                                # 更新self.ais_pick字典(key为mmsi，value为目标id,从1开始计数),并且字典key只更新一次
                                if str(int(key) + 1) not in self.ais_pick.values():
                                    self.ais_pick[mmsi_mode] = str(int(key) + 1)
                                    # 将ais添加到不需要匹配的ais列表里
                                    self.pop_ais.append(mmsi_mode)
            ais_imerge_section3_end = time.time()
            if self.count % (self.init['frame_rate'] * self.init["detail_interval"]) == 0:
                log.logger.info(
                    "第{}帧ais融合section3耗时{:.6}，秒".format(self.count,
                                                        ais_imerge_section3_end - ais_imerge_section3_start))
        except:
            log.logger.error(traceback.format_exc())

    # 每天凌晨，更新所有参数
    def update_para(self):
        self.tracker = KalmanTracking(IOUThreshold=self.init['track_iou_threshold'],
                                      removeTrackAfternFramesThres=self.init['track_remove_after_n_frames_thr'],
                                      uncertaintyCount=self.init['track_uncertainty_count'])
        self.object_list = []  # 存放目标列表，供索引用
        self.object_dict_push = {}  # 存放推送的目标字典（确定目标，用于计算ais融合）
        self.box_count = {}  # 存放每一个待确定目标点的box，动态信息，（用于计算船舶速度、船舶长度）
        self.ais_imerge_info = {}  # 存放ais融合的信息
        self.ais_pick = {}  # ais与目标对应字典{key:mmsi  value:id}
        self.count = 0
        self.pop_ais = []  # 需要剔除的ais信息
        self.ais_imerge_count = 0  # 用于控制ais融合
        self.ais_point_dict_copy = {}  # 深拷贝ais信息，以防多线程在更新字典报错
        self.no_push_id = []  # 不推送的id列表，比如是停泊船
        self.no_push_id_dict = {}  # 不推送的id字典，包含id和box，主要用于不预测停泊船，解决正常船舶与停泊船并行时，id错位（目标确认交并比设置太小时会出现该情况）
        # 删除检测图文件夹
        for root, dirs, files in os.walk(self.init['save_path']):
            try:
                ####过滤掉非根目录文件夹
                if len(dirs) == 0:
                    ####删除文件夹
                    shutil.rmtree(root)
            except:
                log.logger.debug(traceback.format_exc())


if __name__ == '__main__':
    ##videoRead模块参数初始化

    # if reader.runningFlag:
    stop_running()
    stop_running()
